1

我有一个由许多 (2x1) 矩阵组成的单元格数组 A。我有另一个矩阵 B (2x2),我打算将它与单元格 A 的每个元素相乘。换句话说,数组 A 中的每个矩阵都必须与 B 相乘以生成另一个单元格数组 C(与 A 大小相同),包括2x1 矩阵。

视觉上,

B*|A{1,1} A{1,2} ... A{1,n}| = |C{1,1} C{1,2} ... C{1,n}|
  |::::::::::::::::::::::::|   |::::::::::::::::::::::::|
  |A{m,1} A{m,2} ... A{m,n}|   |C{m,1} C{m,2} ... C{m,n}|

这里,C{i,j}=B*A{i,j}

使用cellfun执行此操作非常缓慢。 有没有一种方法可以在不使用显式循环的情况下对其进行矢量化并加速操作而不管 A 和 B 的大小(只要它们是可乘的)?

4

3 回答 3

3

我能想到几个方法。首先,我通过生成一些虚假数据

A = cellfun(@(~)rand(2,1), cell(1000), 'uni', false);
B = rand(2);

细胞乐趣

正如您所说,这是您要避免的。在任何情况下,我都会将其包含在此处进行比较:

C = cellfun(@(x)B*x, A, 'UniformOutput',false);

由于涉及匿名函数,它很慢。带有内置字符串函数(请参阅 参考资料help cellfun)的 Cellfun 正在迅速发展,但是,匿名函数会在每次迭代时强制执行由 Matlab 解释器通过。尽管 JIT 可以在一定程度上提高效率,但远非最佳。

单元格扩展,num2cell,重塑

想法:将单元格扩展为 2x1000 矩阵,执行乘法,然后将结果转换回正确大小的单元格数组。虽然原则上很优雅,但在实践中它变得有点混乱:

C = reshape( num2cell(B*[A{:}],1), size(A) );

请注意,从内存占用的角度来看,中间的 2x1000 临时文件有点浪费……而且,通过num2cell(非内置)和“无用”reshape会大大减慢执行速度。

循环

循环最容易阅读,最容易实现。内存占用小,有利于 JIT 加速等。

C = cell(size(A));
for ii = 1:numel(A)        
   C{ii} = B*A{ii};        
end

唯一的缺点是它的坏名声:)

比较

现在是踢球者:哪一个是最快的?

tic
C = cellfun(@(x)B*x, A, 'uni',false);
toc

tic 
C = reshape( num2cell(B*[A{:}],1), size(A) );
toc

tic
C = cell(size(A));
for ii = 1:numel(A)    
    C{ii} = B*A{ii};    
end
toc

结果:

Elapsed time is 4.738791 seconds.  % cellfun
Elapsed time is 4.161515 seconds.  % cell expansion, num2cell, reshape
Elapsed time is 3.808822 seconds.  % loop

结论:自 R2008 引入 JIT 编译以来,循环不再是邪恶的;默认情况下不要试图避免它们。

于 2013-04-04T12:04:46.483 回答
2

您可以使用mat2cell/cell2mat

A = rand(2, 10);
B = rand(2, 2);
Ac = mat2cell(A, 2, repmat(1, size(A, 2), 1)); % Convert to cell to generate your initial data

Amat = cell2mat(Ac); % Now it's a matrix
Cmat = B * Amat;
C = mat2cell(Cmat, 2, repmat(1, size(A, 2), 1)); % Now it's a cell array again
于 2013-04-04T11:08:11.573 回答
0

我刚试过这个,我希望它是你要找的:

clc,clear all,close all
clc,clear all,close all
A = cell(10,2);
for jj = 1:numel(A)
 A{jj} = rand(2,1);
end

B = rand(2,2);
C = cat(3,A{:});
D = cell(size(A));

for ii = 1:size(C,3)
 D{ii} = B*C(:,:,ii);
end

它包含一个显式for循环(我知道),但在最新的 MATLAB 版本中,性能不应该受到调用for循环的严重影响。

或者您可以使用此答案作为提示。我希望这有帮助。

于 2013-04-04T11:15:27.113 回答