当我在大学的某个时候开始使用matlab时,如果他看到任何不必要的循环(他会要求将其交换为kron
或任何类型的索引操作,我的主管会杀了我)。后来,我试图尽可能地避免在matlab上的任何循环,寻找最黑暗的matlab编码方式来做黑魔法而不是简单的循环。
有一天,我发现了cellfun
,这让黑魔法更加简单,我可以改变很多使用单元格和cellfun
组合的循环,但有一天我看到一个post about cellfun这让我怀疑我的继承matlab知识是否真实,那就是: matlab循环总是比一个内置编译函数慢,这是我非常有信心的东西。我在我的一个实现中测试了它,事实上, for循环会更快!我觉得,OMG,那些日子里做的模糊代码浪费了什么哈哈哈。从那天起,我就停止了努力尝试优化matlab代码,通常它取决于每个案例等等。
今天我saw this answer,它记得我尽量避免尽可能多的matlab循环(我不知道作者是否会为了避免性能,但无论如何它提醒所有这些matlab循环性能的事情)。我想到了一个问题: cellfun比for循环好吗?什么时候会是真的?
答案 0 :(得分:11)
如果性能是一个主要因素,则应避免使用cell,loops或cellfun / arrayfun。 使用向量操作通常要快得多(假设这是可能的)。
下面的代码扩展了Werner的标准数组循环和数组操作的添加示例。
结果是:
代码:
nTimes = 1000;
nValues = 1000;
myCell = repmat({0},1,nValues);
output = zeros(1,nValues);
% Basic operation
tic;
for k=1:nTimes
for m=1:nValues
output(m) = myCell{m} + 1;
end
end
cell_loop_timeAdd=toc;
fprintf(1,'Cell Loop Time %0.4f\n', cell_loop_timeAdd);
tic;
for k=1:nTimes
output = cellfun(@(in) in+1,myCell);
end
cellfun_timeAdd=toc;
fprintf(1,'Cellfun Time %0.4f\n', cellfun_timeAdd);
myData = repmat(0,1,nValues);
tic;
for k=1:nTimes
for m=1:nValues
output(m) = myData(m) + 1;
end
end
loop_timeAdd=toc;
fprintf(1,'Loop Array Time %0.4f\n', loop_timeAdd);
tic;
for k=1:nTimes
output = myData + 1;
end
array_timeAdd=toc;
fprintf(1,'Array Time %0.4f\n', array_timeAdd);
答案 1 :(得分:4)
我将在我自己测试的结果中添加一个答案,但如果人们贡献他们的知识,我会很高兴,这只是我做过的一个简单的测试。
我已经测试了以下条件,单元格大小为1000和1000循环(结果总时间,我可能需要运行超过1000次,因为我的结果有一点波动,但无论如何,这不是科学文章):
因此,似乎带有匿名函数调用的cellfun比简单的for循环慢,但是如果你将使用内置的matlab方法,那么使用cellfun并将其与字符串引用一起使用。对于所有情况都不一定如此,但至少对于测试的功能而言。
已实施的测试代码(我远非优化专家,所以这是代码,以防我做错了):
function ...
[loop_timeAdd,cellfun_timeAdd,...
loop_timeStr,cellfun_timeStr,...
loop_timeBuiltIn,cellfun_timeBuiltInStrInput,...
cellfun_timeBuiltyInFcnHandle,...
loop_timeNonUniform,cellfun_timeNonUniform] ...
= test_cellfun(nTimes,nCells)
myCell = repmat({0},1,nCells);
output = zeros(1,nCells);
% Basic operation
tic;
for k=1:nTimes
for m=1:nCells
output(m) = myCell{m} + 1;
end
end
loop_timeAdd=toc;
tic;
for k=1:nTimes
output = cellfun(@(in) in+1,myCell);
end
cellfun_timeAdd=toc;
% String operation
myCell = repmat({'matchStr'},1,nCells); % Add str that matches
myCell(1:2:end) = {'dontMatchStr'}; % Add another str that doesnt match
output = zeros(1,nCells);
tic;
for k=1:nTimes
for m=1:nCells
output(m) = strcmp(myCell{m},'matchStr');
end
end
loop_timeStr=toc;
tic;
for k=1:nTimes
output = cellfun(@(in) strcmp(in,'matchStr'),myCell);
end
cellfun_timeStr=toc;
% Builtin function (isempty)
myCell = cell(1,nCells); % Empty
myCell(1:2:end) = {0}; % not empty
output = zeros(1,nCells);
tic;
for k=1:nTimes
for m=1:nCells
output(m) = isempty(myCell{m});
end
end
loop_timeBuiltIn=toc;
tic;
for k=1:nTimes
output = cellfun(@isempty,myCell);
end
cellfun_timeBuiltyInFcnHandle=toc;
tic;
for k=1:nTimes
output = cellfun('isempty',myCell);
end
cellfun_timeBuiltInStrInput=toc;
% Builtin function (isempty)
myCell = repmat({'John'},1,nCells);
myCell(1:2:end) = {'Doe'};
output = cell(1,nCells);
tic;
for k=1:nTimes
for m=1:nCells
output{m} = regexp(myCell{m},'John','match');
end
end
loop_timeNonUniform=toc;
tic;
for k=1:nTimes
output = cellfun(@(in) regexp(in,'John','match'),myCell,...
'UniformOutput',false);
end
cellfun_timeNonUniform=toc;
答案 2 :(得分:0)
clear all;
ntimes = 1000;
r = 100;
c = 100;
d = 100;
A = rand(r, c, d);
B = rand(r, c, d);
tic
for i = 1:ntimes
for j = 1 : d
result = A(:, :, j) * B(:, :, j);
end
end
toc
A_cell = num2cell(A, [1 2]);
B_cell = num2cell(B, [1 2]);
tic
for i = 1 : ntimes
result2 = cellfun(@(x, y) x*y, A_cell, B_cell, 'uni', 0);
end
toc
试试吧。再试几次。平均而言,cellfun比双循环更快。
答案 3 :(得分:0)
以下是我通常决定使用哪种解决方案的方法:
bsxfun
吗?做到这一点,它将非常快速,并且希望可读。正如您可能注意到的,我几乎从不使用cellfun来提高性能。这是由于以下逻辑: