Cellfun and arrayfun are generally much slower than simple loop. Their main usecase is to simplify code where performance is not an issue. Better alternative is vectorization which is both fast and concise. (For gpuArrays, arrayfun is faster but that is a special case). Answer from gasapar on reddit.com
Top answer
1 of 3
10

This is interesting. Your examples are performing two different operations, which happen to lead to the same result. It's kind of fun to explore.

TL;DR. You should generally use arrayfun when your input is an array, and cellfun when your input is a cell, although you can often force arrayfun to do the job, with varyig levels of syntax hell.

Fundamentally, arrayfun is meant to operate on arrays and cellfun is meant to operate on cells. But, the Matlab-wise will note that a cell is nothing more than an array of "cells", so arrayfun works anyway.


As you point out, the following two lines perform the same operation:

cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0)   %returns  {'one' 'two' 'three'}
arrayfun(@(c) c(1), {'one' 'two' 'three'});                  %returns  {'one' 'two' 'three'}

However, if we want to do something during our manipulations, it's a little different. For example, we may want to extract the first character of each string. Compare the results of cellfun and arrayfun here:

cellfun( @(c) c(1), {'one' 'two' 'three'}, 'uniformoutput', 0);  %returns {'o' 't' 't'}
arrayfun(@(c) c(1), {'one' 'two' 'three'});                      %Returns {'one' 'two' 'three'}

Do get the same result with arrayfun, we need to dereference the cell within the anonymous function, and then extract the character, and then put the results into a cell array rather than a character array. Like this:

arrayfun(@(c) c{1}(1), {'one' 'two' 'three'},'uniformoutput',false)  %Returns {'o' 't' 't'}

So the difference is that cellfun takes care of the dereference operation which is required to do detailed operations on individual elements of a cell when looping (that is, the {}), whereas arrayfun just performs the standard indexing (that is, the ()). In addition, the 'uniformoutput',false notation determines if the output is written to a regular arral or a cell array.

To show what this means in code, see the following functions which are equivalent to cellfun and arrayfun, both with and without the 'uniformoutput',false notation. These four functions are equivalent except for the use of the () vs. {} within the loop:

function out = cellFunEquivalent(fn, x)
    for ix = numel(x):-1:1
        out(ix) = fn(x{ix});
    end
    out = reshape(out,size(x));
end

function out = arrayFunEquivalent(fn, x)
    for ix = numel(x):-1:1
        out(ix) = fn(x(ix));
    end
    out = reshape(out,size(x));
end

function out = cellFunEquivalent_nonuniform(fn, x)
    for ix = numel(x):-1:1
        out{ix} = fn(x{ix});
    end
    out = reshape(out,size(x));
end

function out = arrayFunEquivalent_nonuniform(fn, x)
    for ix = numel(x):-1:1
        out{ix} = fn(x(ix));
    end
    out = reshape(out,size(x));
end

For the example you posted, the arrayfun function is actually operating on single element cells, and reconstructing a copy of those cells into another array of the same (cell) class (see arrayFunEquivalent). The cellfun operation is dereferencing each element of the input cell array and then reconstructing a copy of those strings into a cell array (see cellFunEquivalent_nonuniform). When the input x is a cell, these operations are equivalent.

2 of 3
4

There are a few built-in functions that can be referenced by name in cellfun but cannot be used in the same way in arrayfun. From the help:

A = CELLFUN('fun', C), where 'fun' is one of the following strings,
returns a logical or double array A the elements of which are computed
from those of C as follows:

   'isreal'     -- true for cells containing a real array, false
                   otherwise
   'isempty'    -- true for cells containing an empty array, false
                   otherwise
   'islogical'  -- true for cells containing a logical array, false
                   otherwise
   'length'     -- the length of the contents of each cell
   'ndims'      -- the number of dimensions of the contents of each cell
   'prodofsize' -- the number of elements of the contents of each cell

So cellfun('isreal', {'one' 'two' 'three'}) is a valid expression, but any similar call with arrayfun will trigger the First input must be a function handle error.

Of course, you can just use @isreal or @isempty for arrayfun

As for why cellfun still exists, I suspect it's historical (don't break backward compatibility)

Discussions

Cellfun to extract arrays from multi-dimensional cell
The idea that for loops are bad in Matlab tends to be over-simplified as it gets passed around so that people start to think that literally any solution that doesn't involve a for loop must be better. It all depends on your aim though. Personally I like cellfun and arrayfun, but if I am doing ... More on mathworks.com
🌐 mathworks.com
1
0
March 27, 2017
array/cellfun vs. for loop
array/cellfun vs. for loop. Learn more about speed, arrayfun, cellfun, for loop, optimization MATLAB More on mathworks.com
🌐 mathworks.com
1
5
June 28, 2012
Use arrayfun and cellfun to avoid for-loops
Hey there, I am currently getting used to all the functions provided by MATLAB, so I am unfortunately not entirely sure how to fully utilize cellfun and arrayfun. I was wondering, whether there ... More on mathworks.com
🌐 mathworks.com
2
0
January 16, 2021
Matlab: arrayfun, cellfun, spfun and structfun vs. simple for-loop - Stack Overflow
Which one is better, using all the *fun functions (arrayfun, cellfun, structfun and spfun) or simply using for loop? What method gives better performance and which methods should be considered bet... More on stackoverflow.com
🌐 stackoverflow.com
🌐
MathWorks
mathworks.com › matlabcentral › answers › 873328-speeding-up-using-cellfunction-and-arrayfun-versus-for-loop
speeding up using cellfunction and arrayfun versus for-loop - MATLAB Answers - MATLAB Central
July 6, 2021 - You code seems to have a great potential for speed improvements. So a comparison of cellfun, arrayfun or loops is not really smart yet. But it is expected, that loops are faster: cellfun and arrayfun are mex functions, which have to call the Matlab level for each element.
🌐
MathWorks
mathworks.com › matlabcentral › answers › 332158-cellfun-to-extract-arrays-from-multi-dimensional-cell
Cellfun to extract arrays from multi-dimensional cell - MATLAB Answers - MATLAB Central
March 27, 2017 - Are you aiming for speed or do you just prefer the readability of cellfun? cellfun, arrayfun and similar functions are generally slower than their for loop counterparts so don't assume that they will be faster.
🌐
MathWorks
mathworks.com › matlab › language fundamentals › data types › cell arrays
cellfun - Apply function to each cell in cell array - MATLAB
A = cellfun(___,Name,Value) applies func with additional options specified by one or more Name,Value pair arguments. For example, to return output values in a cell array, specify 'UniformOutput',false. You can return A as a cell array when func returns values that cannot be concatenated into ...
🌐
MathWorks
mathworks.com › matlabcentral › answers › 718275-use-arrayfun-and-cellfun-to-avoid-for-loops
Use arrayfun and cellfun to avoid for-loops - MATLAB Answers - MATLAB Central
January 16, 2021 - Use arrayfun and cellfun to avoid for-loops. Learn more about cellfun, arrayfun, avoid loops, for loop, performance, runtime optimizing MATLAB
Find elsewhere
🌐
UBC Computer Science
cs.ubc.ca › ~murphyk › Software › matlabTutorial › html › speedup.html
Speedup tricks
In the last example, we used cellfun() function but there is a similar function arrayfun() that applies a function to every element of an array.
🌐
Medium
medium.com › analytics-vidhya › day-1-making-matlab-fun-ad850eaffbde
Day 1: Making MATLAB “fun”
May 27, 2020 - You cannot input an array of cells into cellfun, but you can input a multidimensional cell and operate on each element of the cell. Likewise, you cannot input an array into rowfun which works on tables.
Top answer
1 of 4
11

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:

  • Cell Loop Time - 0.1679
  • Cellfun Time - 2.9973
  • Loop Array Time - 0.0465
  • Array Time - 0.0019

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);
2 of 4
4

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):

  • Basic operation (sum)
    • Simple for loop: 0.2663 s
    • cellfun: 9.4612 s
  • String Operation (strcmp)
    • Simple for loop: 1.3124 s
    • cellfun: 11.8099 s
  • Built-in (isempty)
    • Simple for loop: 8.9042 s
    • cellfun (string input -> see this reference): 0.0105 s
    • cellfun (fcn handle input -> see this reference): 0.9209 s
  • Non-uniform (regexp)
    • Simple for loop: 24.2157 s
    • cellfun (string input): 44.0424 s

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;
Top answer
1 of 2
102

You can get the idea by running other versions of your code. Consider explicitly writing out the computations, instead of using a function in your loop

tic
Soln3 = ones(T, N);
for t = 1:T
    for n = 1:N
        Soln3(t, n) = 3*x(t, n)^2 + 2*x(t, n) - 1;
    end
end
toc

Time to compute on my computer:

Soln1  1.158446 seconds.
Soln2  10.392475 seconds.
Soln3  0.239023 seconds.
Oli    0.010672 seconds.

Now, while the fully 'vectorized' solution is clearly the fastest, you can see that defining a function to be called for every x entry is a huge overhead. Just explicitly writing out the computation got us factor 5 speedup. I guess this shows that MATLABs JIT compiler does not support inline functions. According to the answer by gnovice there, it is actually better to write a normal function rather than an anonymous one. Try it.

Next step - remove (vectorize) the inner loop:

tic
Soln4 = ones(T, N);
for t = 1:T
    Soln4(t, :) = 3*x(t, :).^2 + 2*x(t, :) - 1;
end
toc

Soln4  0.053926 seconds.

Another factor 5 speedup: there is something in those statements saying you should avoid loops in MATLAB... Or is there really? Have a look at this then

tic
Soln5 = ones(T, N);
for n = 1:N
    Soln5(:, n) = 3*x(:, n).^2 + 2*x(:, n) - 1;
end
toc

Soln5   0.013875 seconds.

Much closer to the 'fully' vectorized version. Matlab stores matrices column-wise. You should always (when possible) structure your computations to be vectorized 'column-wise'.

We can go back to Soln3 now. The loop order there is 'row-wise'. Lets change it

tic
Soln6 = ones(T, N);
for n = 1:N
    for t = 1:T
        Soln6(t, n) = 3*x(t, n)^2 + 2*x(t, n) - 1;
    end
end
toc

Soln6  0.201661 seconds.

Better, but still very bad. Single loop - good. Double loop - bad. I guess MATLAB did some decent work on improving the performance of loops, but still the loop overhead is there. If you would have some heavier work inside, you would not notice. But since this computation is memory bandwidth bounded, you do see the loop overhead. And you will even more clearly see the overhead of calling Func1 there.

So what's up with arrayfun? No function inlinig there either, so a lot of overhead. But why so much worse than a double nested loop? Actually, the topic of using cellfun/arrayfun has been extensively discussed many times (e.g. here, here, here and here). These functions are simply slow, you can not use them for such fine-grain computations. You can use them for code brevity and fancy conversions between cells and arrays. But the function needs to be heavier than what you wrote:

tic
Soln7 = arrayfun(@(a)(3*x(:,a).^2 + 2*x(:,a) - 1), 1:N, 'UniformOutput', false);
toc

Soln7  0.016786 seconds.

Note that Soln7 is a cell now.. sometimes that is useful. Code performance is quite good now, and if you need cell as output, you do not need to convert your matrix after you have used the fully vectorized solution.

So why is arrayfun slower than a simple loop structure? Unfortunately, it is impossible for us to say for sure, since there is no source code available. You can only guess that since arrayfun is a general purpose function, which handles all kinds of different data structures and arguments, it is not necessarily very fast in simple cases, which you can directly express as loop nests. Where does the overhead come from we can not know. Could the overhead be avoided by a better implementation? Maybe not. But unfortunately the only thing we can do is study the performance to identify the cases, in which it works well, and those, where it doesn't.

Update Since the execution time of this test is short, to get reliable results I added now a loop around the tests:

for i=1:1000
   % compute
end

Some times given below:

Soln5   8.192912 seconds.
Soln7  13.419675 seconds.
Oli     8.089113 seconds.

You see that the arrayfun is still bad, but at least not three orders of magnitude worse than the vectorized solution. On the other hand, a single loop with column-wise computations is as fast as the fully vectorized version... That was all done on a single CPU. Results for Soln5 and Soln7 do not change if I switch to 2 cores - In Soln5 I would have to use a parfor to get it parallelized. Forget about speedup... Soln7 does not run in parallel because arrayfun does not run in parallel. Olis vectorized version on the other hand:

Oli  5.508085 seconds.
2 of 2
-8

That because!!!!

x = randn(T, N); 

is not gpuarray type;

All you need to do is

x = randn(T, N,'gpuArray');
🌐
Reddit
reddit.com › r/matlab › sort indices of array into a cell according to value using cellfun
r/matlab on Reddit: Sort indices of array into a cell according to value using cellfun
March 23, 2022 -

I have an array, let's call it a, with values. For example

a = [1,1,2,4,5,6,6,8,8,9,10];

it doesn't matter if the array is sorted. Now I do have a second array with the value range, let's call it b

b = unique(a);

what I want to do now is to create a cell which reveals to me at which position of a any possible value of b can be found. For this particular example the cell, let's call it c, would be

c = {1,2},{3},{4},{5},{6,7},{8,9},{10};

A way to do this in a for loop would be

c = cell(1,numel(b));
for i = 1:numel(b)
    c{i} = find(a==b(i));
end

but I desperately want to avoid using this for loop. Can anyone help me? Perhaps a function that does exactly this does already exist? Any help would be much appreciated

🌐
Medium
medium.com › mathworks › which-way-to-compute-cellfun-or-for-loop-bfedfd4b46c0
Which Way to Compute: cellfun or for-loop? | by MathWorks Editor | MathWorks | Medium
November 27, 2019 - If the function handle being called in cellfun takes a long time to evaluate, then the overhead from cellfun will be insignificant. So no big deal to use cellfun in this case.