通过与向量相乘,将2D矩阵扩展为3D矩阵

8

以下是我想要实现的目标:

我有一个矩阵 C

C=[1 2 3; 4 5 6; 7 8 9];

还有一个向量a

a=[1 2];

我希望进行这样的操作,即将a向量的每个元素与C(标量乘法)相乘,并得到一个三维数组D

(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


(:,:,2) =

     2     4     6
     8    10    12
    14    16    18

使用循环肯定可以实现,但由于我需要多次进行此操作,一条语句的代码将会更加方便。

5个回答

11

这是一个非常好的示例,用于展示如何使用bsxfunreshape。虽然@thewaywewalks提议首先调用bsxfun并重塑结果,但我建议相反。这使得bsxfun的一个关键概念——单例维度扩展——更加清晰:

out = bsxfun(@times,C,reshape(a,1,1,[]))

ans(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


ans(:,:,2) =

     2     4     6
     8    10    12
    14    16    18

使用reshape(a,1,1,[]),可以将a放在第三个维度。如果现在应用bsxfun,它将把矩阵Ca的每个元素相乘。


3
在这里,使用“排列”(permute)是否比“重塑”(reshape)更合适呢? - Dan

6

一些reshape和一些bsxfun就可以了:

out = reshape(bsxfun(@mtimes, C(:), a(:).'), [size(C),numel(a)] )

hbaderts的答案所建议的那样,可以使用bsxfun的维度扩展能力,并提供一个排列后的因子向量:

out = bsxfun(@mtimes,C,permute(a,[3,1,2]))

out(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


out(:,:,2) =

     2     4     6
     8    10    12
    14    16    18

6

我有另一种方法可以进行基准测试比较......在语法/可读性方面,这是最简洁的方式,至少我认为是:

out = reshape(kron(a,C),[size(C),numel(a)]);

out(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


out(:,:,2) =

     2     4     6
     8    10    12
    14    16    18

2
我喜欢它,但是 kron 和可读性...... 只有你有一些漂亮的数学背景的话我才会说! - Ander Biguri
或者一些有关那个有用函数的实际操作经验... :) - Adiel

4

编辑(基准测试):由于已经提出了多种解决方案(包括下面的我的解决方案),这里提供一些粗略的基准测试结果来比较不同的解决方案,使用较大的数组:

a=1:10;
N=1000; timers=zeros(N,6);
for ii=1:N; C=rand(400);
  tic; out = repmat(C,[1,1,numel(a)]).*reshape(repelem(a,size(C,1),size(C,2)),[size(C),numel(a)]); timers(ii,1)=toc;
  tic; out = bsxfun(@times,C,reshape(a,1,1,[])); timers(ii,2)=toc;
  tic; out = reshape(C(:)*a, size(C,1), size(C,2), numel(a)); timers(ii,3)=toc;
  tic; out = bsxfun(@mtimes,C,permute(a,[3,1,2])); timers(ii,4)=toc;
  tic; out = reshape(bsxfun(@mtimes, C(:), a(:).'), [size(C),numel(a)] ); timers(ii,5)=toc; 
  tic; out = reshape(kron(a,C),[size(C),numel(a)]); timers(ii,6)=toc;
end;

mean(timers)

ans =

    0.0080863    0.0032406    0.0041718     0.015166    0.0074462    0.0033051

建议使用 @hbaderts 的解决方案最快,其次是 @Adiel's,然后是@Luis Mendo's,@thewaywewalk's(1),然后是我的,最后是@thewaywewalk's (2)。

我的解决方案:

另一种选择是使用repmatreshape(无需使用bsxfun):

out = repmat(C,[1,1,numel(a)]).*reshape(repelem(a,size(C,1),size(C,2)),[size(C),numel(a)])

out(:,:,1) =

 1     2     3
 4     5     6
 7     8     9

out(:,:,2) =

 2     4     6
 8    10    12
14    16    18

这是两个数组的逐元素乘法。 第一个数组是您原始矩阵 C 在第三维度上重复了 numel(a) 次:

repmat(C,[1,1,numel(a)])

ans(:,:,1) =

 1     2     3
 4     5     6
 7     8     9

ans(:,:,2) =

 1     2     3
 4     5     6
 7     8     9

第二个的大小与第一个相同,每个切片都包含a中对应的元素:
reshape(repelem(a,size(C,1),size(C,2)),[size(C),numel(a)])

ans(:,:,1) =

 1     1     1
 1     1     1
 1     1     1

ans(:,:,2) =

 2     2     2
 2     2     2
 2     2     2

4
另一种可能性是使用C矩阵乘法作为列向量,乘以a作为行向量(这将给出所有元素的乘积),然后reshape结果:
out = reshape(C(:)*a, size(C,1), size(C,2), numel(a));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接