Cellfun to extract arrays from multi-dimensional cell
5 views (last 30 days)
Show older comments
Hi all,
Imagine I have a 2-d cell, each cell element is a m by n matrix, I apply SVD on each element such that they are decomposed into left singular vectors, singular values and right singular vectors. Here's an example:
clear; clc;
a = 2;
b = 3;
matL = 5;
matW = 4;
myCell = cell(a, b);
myCell = cellfun(@(v) rand(matL, matW), myCell, 'UniformOutput', false);
[myCellL, myCellSig, myCellR] = ...
cellfun(@(v) svd(v, 'econ'), myCell, 'UniformOutput', false);
Now I'd like to extract the first vector of myCellL, first value of myCellSig, first vector of myCellR, put these into one cell element, and repeat for the second, third...... I can write a loop to do this (continue the above script):
myOtpt = cell(a, b, matW);
for i = 1:a
for j = 1:b
for k = 1:matW
myA = myCellL{i, j}(:, k);
myB = myCellSig{i, j}(k, k);
myC = myCellR{i, j}(:, k);
myOtpt{i, j, k} = {myA, myB, myC};
end
end
end
The second part of script (for loops) seems also is a repeat operation on cells 'myCellL, myCellSig, myCellR', is it possible to write these with cellfun, such that for loop is avoided?
Many thanks!
1 Comment
Adam
on 27 Mar 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.
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 time-sensitive code I will do the tests to actually see what is faster (or any other approaches I can think of).
Avoiding cell arrays altogether if possible would almost certainly be the best way to achieve speed, but it may not be possible.
doc tictoc
is very useful to use though for speed testing. I have done many many short functions (basically scripts, but until the latest Matlab you couldn't define a subfunction in a script) testing the different speeds of cellfun vs for loops etc over the years.
Accepted Answer
Guillaume
on 27 Mar 2017
As Adam says, the loop version may be faster. With a few comments it also would be clearer. You're actually probably better off getting rid of your original svd cellfun and generating the output you want directly with one loop.
Now, if you really want to get rid of the loop, you don't even need a cellfun. It gets hairy though, I'm not going to explain the details:
newCellL = permute(num2cell(cat(3, myCellL{:}), 1), [1 4 2 3]);
newCellSig = reshape(num2cell(diag(blkdiag(myCellSig{:}))), 1, 1, [], numel(myCellSig))
newCellR = permute(num2cell(cat(3, myCellR{:}), 1), [1 4 2 3]);
newOtpt = permute(reshape(num2cell(cat(2, newCellL, newCellSig, newCellR), 2), [], size(myCell, 1), size(myCell, 2)), [2 3 1]);
A lot of array concatenation, splitting and dimension manipulation (plus some diag(blkdiag) to get the diagonal of all the matrices in one go. It's possible you could optimise the first three permute so that the 4th permute is not required, but it hurts my head already enough as it is.
2 Comments
Adam
on 28 Mar 2017
It's mostly a matter of preference if the code in question is not time-sensitive.
I like one line arrayfun or cellfun implementations personally, but I know people who find them less readable than for loops also.
More Answers (0)
See Also
Categories
Find more on Logical in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!