MATLAB: Using cellfun with multi level cell array - matlab

I have a multi-level cell array. The individual levels could be of different size. I am wondering how I can apply cellfunto the lowest level. Imagine the following mulit-level cell array:
a = {randi(10,5,1), randi(5,5,1)}
b = randi(100,5,1,10)
f = {a,b}
Now, I would like to drill down as much as possible and apply cellfun to the deepest level possible of f. At the and of each level, there is a 2D/3D matrix. Let's say, I simply want to add 5 to each value. What's the most efficient way?
Here's the result I am looking for.
[a_nRows, a_nCols, a_nPages] = size(a)
x = cellfun(#plus, f{1}, repmat({5}, a_nRows, a_nCols, a_nPages), 'UniformOutput', false)
y = cellfun(#plus, f(2), {5}, 'UniformOutput', false)

You can use recursion for this.
Firstly, define a function which does one of two things
If the input is a numeric matrix, apply some operation.
If the input is a cell, call this same function with the cell's contents as inputs.
The function would look something like this (defined locally to another function or in its own m file):
function out = myfunc( in, op )
if iscell( in )
out = cellfun( #(x) myfunc(x, op), in, 'UniformOutput', false );
elseif isnumeric( in )
out = op( in );
else
error( 'Cell contents must be numeric or cell!' )
end
end
Then you can call myfunc on your cell. Here is an example similar to yours:
a = {[1 2; 3 4], {eye(2), 10}}; % Nested cell arrays with numeric contents
op = #(M) M + 5; % Some operation to apply to all numeric contents
myfunc( a, op )
% >> ans =
% { [6 7; 8 9], {[6 5; 5 6], 15}}
Directly using your example, the output of myfunc(f, #(M)M+5) is the same as your {x, y{1}} - i.e. the operation op is applied to every cell and nested cell with the result structured the same as the input.

Related

cellfun with two arrays of indices

I have one big cell with N by 1 dimension. Each row is either a string or a double. A string is a variable name and the sequential doubles are its values until the next string (another variable name). For example:
data = {
var_name1;
val1;
val2;
val3;
val4;
val5;
var_name2;
val1;
val2;
var_name3;
val1;
val2;
val3;
val4;
val5;
val6;
val7}
and so on. I want to separate the data cell into three cells; {var_name and it's 5 values}, {var_name and it's 2 values}, {var_name and it's 7 values}. I try not to loop as much as possible and have found that vectorization along with cellfun works really well. Is it possible? The data cell has close to million rows.
I believe the following should do what you're after. The main pieces are to use cumsum to work out which name each row corresponds to, and then accumarray to build up lists per name.
% Make some data
data = {'a'; 1; 2; 3;
'b'; 4; 5;
'c'; 6; 7; 8; 9;
'd';
'e'; 10; 11; 12};
% Which elements are the names?
isName = cellfun(#ischar, data);
% Use CUMSUM to work out for each row, which name it corresponds to
whichName = cumsum(isName);
% Pick out only the values from 'data', and filter 'whichName'
% for just the values
justVals = data(~isName);
whichName = whichName(~isName);
% Use ACCUMARRAY to build up lists per name. Note that the function
% used by ACCUMARRAY must return something scalar from a column of
% values, so we return a scalar cell containing a row-vector
% of those values
listPerName = accumarray(whichName, cell2mat(justVals), [], #(x) {x.'});
% All that remains is to prepend the name to each cell. This ends
% up with each row of output being a cell like {'a', [1 2 3]}.
% It's simple to make the output be {'a', 1, 2, 3} by adding
% a call to NUM2CELL on 'v' in the anonymous function.
nameAndVals = cellfun(#(n, v) [{n}, v], data(isName), listPerName, ...
'UniformOutput', false);
cellfun is for applying a function to each element of a cell.
When you pass multiple arguments to cellfun like that, it takes the ith argument of data, indx_first, and indx_last, and uses each of them in the anonymous function. Substituting those variables in, your function evaluates to x(y : z), for each element x in data. In other words, you're doing data{i}(y : z), i.e., indexing the actual elements of the cell array, rather than indexing the cell array itself. I don't think that's what you want. Really you want data{y : z}, for each (y, z) pair given by corresponding elements in indx_first and indx_last, right?
If that's indeed the case, I don't see a vectorized way to solve your problem, because each of the "variables" has different size. But you do know how many variables you have, which is the size of indx_first. So I'd pre-allocate and then loop, like so:
>> vars = cell(length(indx_first), 2);
>> for i = 1:length(vars)
vars{i, 1} = data{indx_first(i) - 1}; % store variable name in first column
vars{i, 2} = [data{indx_first(i) : indx_last(i)}]; % store data in last column
end
At the end of this, you'll have a cell array with 2 columns. The first column in each row is the name of the variable. The second is the actual data. I.e.
{'var_name1', [val1 val2 val3 val4 val5];
'var_name2', [val1 val2];
.
.
.

Best way to count all elements in a cell array?

I want to count all elements in a cell array, including those in "nested" cells.
For a cell array
>> C = {{{1,2},{3,4,5}},{{{6},{7},{8}},{9}},10}
C = {1x2 cell} {1x2 cell} [10]
The answer should be 10.
One way is to use [C{:}] repeatedly until there are no cells left and then use numel but there must be a better way?
Since you are only interested in the number of elements, here is a simplified version of flatten.m that #Ansari linked to:
function n = my_numel(A)
n = 0;
for i=1:numel(A)
if iscell(A{i})
n = n + my_numel(A{i});
else
n = n + numel(A{i});
end
end
end
The result:
>> C = {{{1,2},{3,4,5}},{{{6},{7},{8}},{9}},10};
>> my_numel(C)
ans =
10
EDIT:
If you are feeling lazy, we can let CELLPLOT do the counting:
hFig = figure('Visible','off');
num = numel( findobj(cellplot(C),'type','text') );
close(hFig)
Basically we create an invisible figure, plot the cell array, count how many "text" objects were created, then delete the invisible figure.
This is how the plot looks like underneath:
Put this in a function (say flatten.m) (code from MATLAB Central):
function C = flatten(A)
C = {};
for i=1:numel(A)
if(~iscell(A{i}))
C = [C,A{i}];
else
Ctemp = flatten(A{i});
C = [C,Ctemp{:}];
end
end
Then do numel(flatten(C)) to find the total number of elements.
If you don't like making a separate function, you can employ this clever (but nasty) piece of code for defining a flatten function using anonymous functions (code from here):
flatten = #(nested) feval(Y(#(flat) #(v) foldr(#(x, y) ifthenelse(iscell(x) | iscell(y), #() [flat(x), flat(y)], #() {x, y}), [], v)), nested);
Either way, you need to recurse to flatten the cell array then count.

Can I specify nargout as part of a MATLAB function call?

The problem:
I want to index into the result of a function call that returns a variable number of output arguments without storing the result in a temporary.
getel = #(x,i) x(i); #% simple anonymous function to index into a vector
x = zeros(2,2,2);
row = getel(ind2sub(size(x), 8), 1) #% desired: 2 (row 2)
#% actual: 8 (linear index)-because ind2sub is returning 1 value only
[row col dep]=ind2sub(size(x),8) #% row=2, ind2sub returning 3 values
Example usage:
x(1).val1 = [1 2 3];
x(1).val2 = [2 1 2];
x(2).val1 = [2 1 2];
x(2).val2 = [1 0 0];
#% The normal way I would do this, with a temporary variable
[~,ind] = min(x(1).val2); #% ind=2
v(1) = x(1).val1(ind);
[~,ind] = min(x(2).val2); #% ind=2
v(2) = x(2).val1(ind);
#% I'd like to be able to do this with arrayfun:
v = arrayfun(#(s) s.val1(min(s.val2), x);
-------^ returns value of minimum, not index
The above arrayfun doesn't work - the form of min that is called returns one output: the minimum value. To make it work right, one option would be the following hypothetical function call:
v = arrayfun(#(s) s.val1(getoutputnum(2, 2, #min, s.val2)), x);
hypothetical function -----------^ ^ ^ ^-func ^--func args
which form (nargout) of func ---| |- which arg to return
I realize that for the above scenario, I could use
s.val1(find(s.val2==min(s.val2),1,'first'))
or other tricks, but that isn't possible in all cases.
In the case of ind2sub, I may want to know the index into a particular dimension (columns, say) - but the 1-output form of the function returns only a linear index value - the n-dimensional form needs to be called, even if the value of dimension 1 is what I care about.
Note: I realize that writing a function file would make this trivial: use ~ and the [out] = func(in) form. However, when writing scripts or just on the command line, it would be nice to be able to do this all within anonymous functions. I also realize that there are undoubtedly other ways to get around the problem; I would just like to know if it is possible to specify which form of a function to call, and perhaps which output number to be returned, without using the out=func(in) syntax, thus allowing functions to be nested much more nicely.
Could you do something like this?
In its own file:
function idx=mymin(x)
[~,idx] = min(x);
In your code:
v = arrayfun(#(s) s.val1(mymin(s.val2), x);
Might have syntax errors; I don't have MATLAB on the computer I'm writing this on. The idea is there though: just wrap MATLAB's min and capture the second argument, which is the logical indexing for the position of the minimum value in x.
I can get ind2sub() to return the variable number of args like this:
x = zeros(2,2,2);
c = cell(ndims(x),1);
[c{:}] = ind2sub(size(x), 8);
The c cell array will now have the 3D indices c = {2;2;2}.
[c{:}] = ind2sub(size(x), 2);
would produce c = {2;1;1}.
Is this what you were looking for?

split a list into several variables in matlab

If I have a short list (let's say two or three elements) I would like to have function that split it in several variables. Something like that:
li=[42 43];
[a b]=split(li)
--> a=42
--> b=43
I am looking for some way to make my code shorter in matlab. This one would be nice in some situations For instance:
positions=zeros(10,3);
positions= [....];
[x y z]=split(max(positions,1))
instead of doing:
pos=max(positions,1)
x=pos(1);
y=pos(2);
z=pos(3);
The only way I know of to do this is to use deal. However this works with cell arrays only, or explicit arguments in to deal. So if you want to deal matrices/vectors, you have to convert to a cell array first with num2cell/mat2cell. E.g.:
% multiple inputs
[a b] = deal(42,43) % a=2, b=3
[x y z] = deal( zeros(10,1), zeros(10,1), zeros(10,1) )
% vector input
li = [42 43];
lic = num2cell(li);
[a b]=deal(lic{:}) % unforunately can't do num2cell(li){:}
% a=42, b=43
% matrix input
positions = zeros(10,3);
% create cell array, one column each
positionsc = mat2cell(positions,10,[1 1 1]);
[x y z] = deal(positionsc{:})
The first form is nice (deal(x,y,...)) since it doesn't require you to explicitly make the cell array.
Otherwise I reckon it's not worth using deal when you have to convert your matrices to cell arrays only to convert them back again: just save the overhead. In any case, it still takes 3 lines: first to define the matrix (e.g. li), then to convert to cell (lic), then to do the deal (deal(lic{:})).
If you really wanted to reduce the number of lines there's a solution in this question where you just make your own function to do it, repeated here, and modified such that you can define an axis to split over:
function varargout = split(x,axis)
% return matrix elements as separate output arguments
% optionally can specify an axis to split along (1-based).
% example: [a1,a2,a3,a4] = split(1:4)
% example: [x,y,z] = split(zeros(10,3),2)
if nargin < 2
axis = 2; % split along cols by default
end
dims=num2cell(size(x));
dims{axis}=ones([1 dims{axis}]);
varargout = mat2cell(x,dims{:});
end
Then use like this:
[a b] = split([41 42])
[x y z]= split(zeros(10,3), 2) % each is a 10x1 vector
[d e] = split(zeros(2,5), 1) % each is a 1x5 vector
It still does the matrix -> cell -> matrix thing though. If your vectors are small and you don't do it within a loop a million times you should be fine though.
You can extract the values in the list into different variables with
li = [42 43 44];
tmp = num2cell(li);
[a b c] = deal(tmp{:})
a =
42
b =
43
c =
44
You can manage this in a single expression if you really wanted to:
a = [1, 2, 3, 4]
[b, c, d, e]=feval(#(x)x{:}, num2cell(a))
Result:
b =
1
c =
2
d =
3
e =
4
If you wanted to use this a lot you could quickly make an anonymous function:
expand = #(A) feval(#(x)x{:}, num2cell(A))
[b, c, d, e]=expand(a)
I believe this would work on anything that num2cell will accept, which doesn't even have to be numeric, just needs to be an array, which almost everything in Matlab is.

Map function in MATLAB?

I'm a little surprised that MATLAB doesn't have a Map function, so I hacked one together myself since it's something I can't live without. Is there a better version out there? Is there a somewhat-standard functional programming library for MATLAB out there that I'm missing?
function results = map(f,list)
% why doesn't MATLAB have a Map function?
results = zeros(1,length(list));
for k = 1:length(list)
results(1,k) = f(list(k));
end
end
usage would be e.g.
map( #(x)x^2,1:10)
The short answer: the built-in function arrayfun does exactly what your map function does for numeric arrays:
>> y = arrayfun(#(x) x^2, 1:10)
y =
1 4 9 16 25 36 49 64 81 100
There are two other built-in functions that behave similarly: cellfun (which operates on elements of cell arrays) and structfun (which operates on each field of a structure).
However, these functions are often not necessary if you take advantage of vectorization, specifically using element-wise arithmetic operators. For the example you gave, a vectorized solution would be:
>> x = 1:10;
>> y = x.^2
y =
1 4 9 16 25 36 49 64 81 100
Some operations will automatically operate across elements (like adding a scalar value to a vector) while others operators have a special syntax for element-wise operation (denoted by a . before the operator). Many built-in functions in MATLAB are designed to operate on vector and matrix arguments using element-wise operations (often applied to a given dimension, such as sum and mean for example), and thus don't require map functions.
To summarize, here are some different ways to square each element in an array:
x = 1:10; % Sample array
f = #(x) x.^2; % Anonymous function that squares each element of its input
% Option #1:
y = x.^2; % Use the element-wise power operator
% Option #2:
y = f(x); % Pass a vector to f
% Option #3:
y = arrayfun(f, x); % Pass each element to f separately
Of course, for such a simple operation, option #1 is the most sensible (and efficient) choice.
In addition to vector and element-wise operations, there's also cellfun for mapping functions over cell arrays. For example:
cellfun(#upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans =
'A' 'B' 'C'
If 'UniformOutput' is true (or not provided), it will attempt to concatenate the results according to the dimensions of the cell array, so
cellfun(#upper, {'a', 'b', 'c'})
ans =
ABC
A rather simple solution, using Matlab's vectorization would be:
a = [ 10 20 30 40 50 ]; % the array with the original values
b = [ 10 8 6 4 2 ]; % the mapping array
c = zeros( 1, 10 ); % your target array
Now, typing
c( b ) = a
returns
c = 0 50 0 40 0 30 0 20 0 10
c( b ) is a reference to a vector of size 5 with the elements of c at the indices given by b. Now if you assing values to this reference vector, the original values in c are overwritten, since c( b ) contains references to the values in c and no copies.
It seems that the built-in arrayfun doesn't work if the result needed is an array of function:
eg:
map(#(x)[x x^2 x^3],1:10)
slight mods below make this work better:
function results = map(f,list)
% why doesn't MATLAB have a Map function?
for k = 1:length(list)
if (k==1)
r1=f(list(k));
results = zeros(length(r1),length(list));
results(:,k)=r1;
else
results(:,k) = f(list(k));
end;
end;
end
If matlab does not have a built in map function, it could be because of efficiency considerations. In your implementation you are using a loop to iterate over the elements of the list, which is generally frowned upon in the matlab world. Most built-in matlab functions are "vectorized", i. e. it is more efficient to call a function on an entire array, than to iterate over it yourself and call the function for each element.
In other words, this
a = 1:10;
a.^2
is much faster than this
a = 1:10;
map(#(x)x^2, a)
assuming your definition of map.
You don't need map since a scalar-function that is applied to a list of values is applied to each of the values and hence works similar to map. Just try
l = 1:10
f = #(x) x + 1
f(l)
In your particular case, you could even write
l.^2
Vectorizing the solution as described in the previous answers is the probably the best solution for speed. Vectorizing is also very Matlaby and feels good.
With that said Matlab does now have a Map container class.
See http://www.mathworks.com/help/matlab/map-containers.html