简体   繁体   中英

When and why should I use cellfun in Matlab?

I have a question regarding the cellfun function in MATLAB.

When / why should I use it, and when may I just as well drop it?

A simple example: Let's say I have a cell a , and I want to find the average of all values in a .

a{1} = [1 2;3 4];
a{2} = [1 2 3;4 5 6; 7 8 9];

My approach would be something like:

mean([a{1}(:); a{2}(:)])

What will the appropriate cellfun version of this be, and is it any better?

I've tried doing something like this, (obviously not working):

mean_a = mean(cellfun(@mean, a,'UniformOutput',0))

Thanks!

It of course depends in what you want to do. cellfun is intended to act separately on each cell in your cell array. If you want to take a global mean of your cell array values, and insist on using cellfun then this should work:

mean_a = mean(cell2mat(cellfun(@mean, a,'UniformOutput',0)))

cellfun is just like looping through the cell matrix and
executing specified function separately on each cell.
It's usually faster than doing the same thing explicitly
in loop, but the basic difference is that its easy to
write and read - its immediately clear what the call is
doing. But you could just as well write the loop yourself.

In your specific case you could use cellfun this way:

mean_a = mean(cellfun(@(x) mean(x(:)), a));

If you have thousands of cells and you want to do something
to each of them you either use a loop or a cellfun
BTW: @(x) means that you want the content of each cell
to be understood as x so that mean(x(:)) gives you what
you want - mean of the whole matrix content of the cell.

Based on your attempted solution, I imagine that the answers given will solve your problem. However, it appears to me your solution will weight some values more than others and may not be valuable to all readers.
Using your matrices,

mean([a{1}(:); a{2}(:)]) ~= mean([mean(a{1}(:)) mean(a{2}(:))])
                  4.2308 ~= 3.75

This is the case where numel(a{1}) ~= numel(a{2}).

The accepted solution is equivalent to the right side of the above equation, but the original implementation is (obviously) equal to the left side. Either could be correct given your needs.

For balance, I offer one (of many) ways to accomplish a non-weighted mean of all the elements of your cell by reshaping each matrix to a column array and concatenating them:

b = cellfun(@(x) reshape(x, 1, []), a, 'UniformOutput', false);
mean_a = mean([b{:}])

I love using cellfun for plotting operations instead of looping, for example if I have multiple sets of sensor data and each set has multiple columns (because of multiple sensors per set) it's very convenient using

numOfSensors = 5;
numOfSets = 6;

%% sample data preparation
x = 1:100;
y = rand(length(x), numOfSets*numOfSensors);
yCell = mat2cell(y, 100, numOfSensors*ones(1,numOfSets)); % this is my sensor data
scaleCell = num2cell(fliplr(cumsum(1:numOfSets)));
yCell = cellfun(@(x, scale)x.*scale, yCell, scaleCell, 'unif', false);

%% plot preparation
nameCell = arrayfun(@(x)['sensor set ' num2str(x)], 1:numOfSets, 'unif', false);
colorCell = num2cell(lines(numOfSets), 2)';

%% plot
figure, hold all,
set(gca, 'ColorOrder', [0 0 0], 'LineStyleOrder', {'-','--','-*','-.',':'})
h = cellfun(@(y, name, c)plot(x, y, 'linewidth', 1.5, 'displayName', name, 'color', c), yCell, nameCell, colorCell, 'unif', false);
hh = cellfun(@(x)x(1), h, 'unif', false);
legend([hh{:}])

instead of looping. This example plots all datasets, each dataset in it's own color and each sensor per dataset with an other linestyle. The legend is displayed for each data set only (note: this could also be done by using hggroups).

Or a simpler using case - I have a cell array of data again and want to have a short view at it:

figure, hold all, cellfun(@plot,dataCell)

That's it, one line, very fast in the command line.

Another great use case is compressing higher dimensional data numerical data by using mean(), max(), min(), std() and so on, but you've mentioned this already. This gets even more important if the data is not of uniform size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM