Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I apply a function with multiple parameters using `cellfun` (MATLAB)?

Using cellfun, how do I apply a function to all the cells created by the mat2cell function? My function is defined in another file, here it is referred to by myFunc. This function takes two arguments, which should be a cell and an integer.

e.g. function H = myFunc(img,Q)

My code is as follows:

% Split into grid and process each cell
width = size(img,2) % get image width
height = size(img,1) % get image height
depth = size(img,3) % get depth
C = mat2cell(img,[height/2 height/2],[width/2 width/2],[depth/2 depth/2]); % divides image into sections
F = cellfun(@myFunc,C);
save(fout,'F');

The issue is of course with the line F = cellfun(@myFunc,C);. How do I pass the cells and a chosen integer e.g. 4 into myFunc for each cell?

Many thanks.

like image 716
petehallw Avatar asked Feb 26 '15 13:02

petehallw


People also ask

How does Cellfun work in Matlab?

Description. A = cellfun( func , C ) applies the function func to the contents of each cell of cell array C , one cell at a time. cellfun then concatenates the outputs from func into the output array A , so that for the i th element of C , A(i) = func(C{i}) .

How do you use a cell array in Matlab?

C = cell( n ) returns an n -by- n cell array of empty matrices. C = cell( sz1,...,szN ) returns a sz1 -by-... -by- szN cell array of empty matrices where sz1,...,szN indicate the size of each dimension. For example, cell(2,3) returns a 2-by-3 cell array.

How do you convert a cell to an array in Matlab?

A = cell2mat( C ) converts a cell array into an ordinary array. The elements of the cell array must all contain the same data type, and the resulting array is of that data type. The contents of C must support concatenation into an N-dimensional rectangle. Otherwise, the results are undefined.


3 Answers

Recently came across this problem, and noticed that while Octave has implicit cell expansion of parameters in cellfun, Matlab doesn't. Calling an anonymous function has more overhead than calling the function directly (although Matlab is not nearly as bad as Octave in that regard) so I found passing the parameter as a cell array to be a bit faster, shown here with a simple example:

abc = {magic(2), magic(3), magic(4)}
abc =
  3×1 cell array
    {2×2 double}
    {3×3 double}
    {4×4 double}
    
def = cellfun (@(x) sum(x,2), abc, "UniformOutput", false) %anonymous function method
def =
  3×1 cell array
    {2×1 double}
    {3×1 double}
    {4×1 double}
def{:}
ans =
     4
     6
ans =
    15
    15
    15
ans =
    34
    34
    34
    34 

expanding the parameter into a cell array and passing it as another input produces the same correct output:

def = cellfun (@sum, abc, num2cell(2*ones(size(abc))), "UniformOutput", false) % cell expansion method
def =
  3×1 cell array
    {2×1 double}
    {3×1 double}
    {4×1 double}
def{:}
ans =
     4
     6
ans =
    15
    15
    15
ans =
    34
    34
    34
    34 
    

a quick tic/toc check shows this to be a bit faster in Matlab 2021a:

tic; 
for idx = 1:100000
  cellfun(@(x) sum(x,2), abc,"UniformOutput",false); 
end
toc
Elapsed time is 4.017116 seconds.

tic, 
for idx = 1:100000
  cellfun(@sum, abc, num2cell(2*ones(size(abc))),"UniformOutput",false);
end
toc
Elapsed time is 1.217712 seconds

I haven't tried this with non-simple parameters, but repmat could do the same for, say, string inputs, but repmat seems to add quite a bit back to the overhead:

tic
for idx = 1:100000
    cellfun(@sum, abc, repmat({2}, size(abc)),"UniformOutput",false); 
end
toc
Elapsed time is 4.367002 seconds.

So perhaps there's a better way to expand those. Take note that this is a very simple test case with a small array, and that this time savings may not hold true as things scale up, or as you add multiple parameters. Also, you are multiplying the memory requirement for each parameter you do this with, as each is expanded to the size of the input array.

A quick test shows the same time savings hold true with a custom myfunc as with a matlab function like sum.

like image 178
Nick J Avatar answered Oct 21 '22 01:10

Nick J


Well, simply define a new anonymous function as @(x) myFunc(x,4) and use it this way:

F = cellfun(@(x) myFunc(x,4), C)
like image 35
knedlsepp Avatar answered Oct 20 '22 23:10

knedlsepp


By using an anonymous function:

F = cellfun(@(Q) myFunc(Q,4),C);
like image 27
Christopher Creutzig Avatar answered Oct 20 '22 23:10

Christopher Creutzig