When I started working with matlab sometime ago in the university, my supervisor would kill me if he saw any unnecessary for loop (he would ask for exchanging it for kron
or any type of indexes manipulation as possible). Later on, I was trying to avoid as much as possible any loop on matlab, searching for the darkest matlab coding ways to do black magic instead of a simple loop.
And one day I discovered the cellfun
, which made the black magic quite simplier, I could change many loops working with cells and cellfun
combo, but one day I saw one post about cellfun which made me question if my inherited matlab knowledge was true, that is: that matlab loops would always be slower than one builtin compiled function, which was something I had so much faith. I tested it in one of my implementations and in fact, the for loop would be faster! I was like, OMG, all those days doing obscure code wasted for nothing hahaha. Since that day, I stopped working that hard to try to optimize matlab code, normally it depends for each case and so on.
Today I saw this answer, which remembered my effort for avoiding as much matlab loops as possible (I don't know if that was the author will to avoid for performance, but anyway it reminded all this matlab loop performance thing). And one question came to my mind: Is cellfun better than for loops? When would that be true?
For the example Tom gave, however, cellfun with string is much faster than a for loop (in answer to the original question). Elapsed time is 0.755874 seconds. Elapsed time is 0.913470 seconds. Elapsed time is 0.021828 seconds.
For example, I tested arrayfun vs a forloop, squaring the elements, and the speed difference was a factor of two. While this is concrete evidence that we should always use for loops instead of arrayfun, it's obvious that the benefit varies.
arrayfun can be significantly slower than an explicit loop in matlab.
If performance is a major factor you should avoid using cells, loops or cellfun/arrayfun. It's usually much quicker to use a vector operation (assuming this is possible).
The code below expands on Werner's add example with standard array loop and array operations.
The results are:
Code:
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);
I will add one answer with the results that I tested myself, but I would be glad if people contribute with their knowledge, this is just a simple test I've made.
I've tested the following conditions with cell size of 1000 and 1000 loops (results on total time, and I would probably have to run more than 1000 times, because I am having a little fluctuation on the results, but anyway, this is not a scientific article):
So, it seems that cellfun with anonymous function calls are slower than a simple for loop, but if you will use a builtin matlab method, do it with cellfun and use it with the string quotation. This is not necessarily true for all cases, but at least for the tested functions.
The implemented test code (I am far from being an optimization specialist, so here is the code in case I did something wrong):
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With