Extract specific values from cell based on array in MATLAB - arrays

I want to extract some certain values from a simple cell-array, which looks like:
CellExample{1} = [1,54,2,3,4]
CellExample{2} = [1,4,1,92,9,0,2]
...
And I have an additional array that tells me which element I want to extract from each Cell element. The array is as long as the cell:
ArrayExample = [2,4,...]
Basically, I want an array that says:
Solution(1) = CellExample{1}(ArrayExample(1)) = 54
Solution(2) = CellExample{2}(ArrayExample(2)) = 92
I have thought of using cellfun, but I have still some troubles using it correctly, e.g.:
cellfun(#(x) x{:}(ArrayExample),CellExample,'UniformOutput',false)

The following
Cell{1} = [1,54,2,3,4]
Cell{2} = [1,4,1,92,9,0,2]
cellfun(#(x) disp(x), Cell)
is equivalent to the loop
for ii = 1:numel(Cell)
disp(Cell{ii})
end
that is, cellfun() already passes the content of each cell to the anonymous function.
However, since you want to pass a numeric array as the second input to the anonymous function, and cellfun() accepts only cell() inputs, you need to use arrayfun(), which does NOT unpack cell content.
In your case:
arrayfun(#(c,pos) c{1}(pos), Cell, Array)
and it is equivalent to:
for ii = 1:numel(Cell)
Cell{ii}(Array(ii))
end

Related

Targeting specific elements of cell arrays (Matlab)

I currently have a cell array consisting of 7x1 vectors. I need to extract the first element (1,1) of each vector from each cell and store these values in a new array. This is what I currently have:
for j = 1:numel(xvalues)
cellj = xvalues{j};
a = cellj(1:1);
avalues(1:j) = a;
end
However, I am just generating a cell array with the first element of the last cell, repeating.
How can I fix this?
You can also use cellfun to apply a function to each element in a cell array. So to extract the first element of each vector the following should work.
avalues = cellfun(#(x) x(1),xvalues);
Cellfun loops through each element in the cell array and passes it in to the anonymous function via #(x). We then process x by taking the first element x(1).
In cases such as yours, where the cell contents are matrices of the same size, and assuming your inputs are small enough (meaning that neither memory nor runtime are imminent issues) you can convert the cell array into a numeric matrix and select a vector along the relevant dimension:
function out = q48740494
%% Generate some data:
c = squeeze(num2cell(randi(20,7,1,20),[1,2]));
% c = 20×1 cell array of {7x1 double}
%% Convert this into a numeric array and output:
out = cell2mat(c.'); out = out(1,:);
% BONUS: another version of the line above.
% out = subsref(cell2mat(c.'), substruct('()', {1,1:numel(c)}) ) ;

Store big structure in Matlab

I am fitting a statistical model in matlab using fitglm which returns a structure mdl. I would like to store many such structures in an array of cells to reuse them later but this seems not to work. Here is the code:
models = cell(size(quarterList,1)-lag-1,1);
for i=1:size(quarterList,1)-lag-1
%indicesTemp = find(and(annQuarters(:,2) <= quarterList(i+11,2),annQuarters(:,2) >= quarterList(i,2)));
memberTemp = ismember(annQuarters(:,:), quarterList(i:i+lag,:));
indicesTemp = find(memberTemp(:,2));
fprintf('Perdiod: Q%i %i to Q%i %i - Nb samples: %i \n',annQuarters(i,1),annQuarters(i,2),annQuarters(i+lag,1),annQuarters(i+lag,2),size(indicesTemp,1));
[Xtemp Ytemp] = categorizeVariables(X(indicesTemp,:),Y(indicesTemp,:));
mdl = fitglm(Xtemp,Ytemp-1,'Distribution','binomial', 'Link','logit');
models(i,1) = mdl;
end
Now when I try to assign such structure to a single cell, it works:
temp = cell(1,1);
mdl = fitglm(Xtemp,Ytemp-1,'Distribution','binomial', 'Link','logit');
temp = mdl;
Why is the assignment in the array of cells not working in that case? Any suggestion on how to go around this?
This doesn't work because using models(index) assignment (with ()) assumes that the thing on the right side is a cell. You instead want to use curly brackets which will copy the item on the right (of any type) into the cell array at the specified element.
models{i,1} = mdl;
If you really wanted to use (), you could instead convert the thing on the right to a cell first.
models(i,1) = {mdl};
The reason that your second example (with a scalar cell array) doesn't result in an error is because you aren't putting the output of fitglm into the cell array but rather overwriting the variable temp to point to mdl instead of the cell array.
temp = cell(1,1);
% Check if temp is a cell
iscell(temp)
%// TRUE
mdl = fitglm(Xtemp,Ytemp-1,'Distribution','binomial','Link','logit');
temp = mdl;
% Check if temp is still a cell (it isn't)
iscell(temp)
%// FALSE
All of that aside, you can actually store structs within an array themselves. You don't actually need a cell array unless the fields are different.
for i = 1:N
mdl(i) = fitglm(Xtemp, Ytemp - 1, 'Distribution', 'binomial', 'Link', 'logit');
end

How to name variables in a data array using a for loop

I have an array within an array and I am trying to name the variables using a for loop as there are a lot of variables. When I use the following simple code Time1 = dataCOMB{1,1}{1,1}(1:1024, 1); it opens the first cell in an array and proceeds to open the first cell in the following array and finally defines all the values in column 1 rows 1 to 1024 as Time1. However I have 38 of these different sets of data and when I apply the following code:
for t = 1:38
for aa = 1:38
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
end
end
I get an error
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in Load_Files_working (line 39)
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
Basically I am trying to get matlab to call the first column in each data set Time1, Time2, etc.
The problem:
1)You'd want to extract in a cell row...
2) ...the first 1024 numbers in the 1st column...
3) ...from each of the first 38 cells of a cell array.
The plan:
1) If one wants to get info from each element of a cell array (that is, an array accessed via {} indexing), one may use cellfun. Calling cellfun(some_function, a_cell_array) will aggregate the results of some_function(a_cell_array{k}) for all possible k subscripts. If the results are heterogeneous (i.e. not having the same type and size), one may use the cell_fun(..., 'UniformOutput', false) option to put them in an output cell array (cell arrays are good at grouping together heterogeneous data).
2) To extract the first 1024 numbers from the first column of an numeric array x one may use this anonymous function: #(x) x(1:1024,1). The x argument will com from each element of a cell array, and our anonymous function will play the role of some_function in the step above.
3) Now we need to specify a_cell_array, i.e. the cell array that contains the first 38 cells of the target. That would be, simply dataCOMB{1,1}(1,1:38).
The solution:
This one-liner implements the plan:
Time = cellfun(#(x) x(1:1024,1), dataCOMB{1,1}(1,1:38), 'UniformOutput', false);
Then you can access your data as in this example:
this_time = Time{3};
Your error is with Time(t). That's not how you create a new variable in matlab. To do exactly what you want (ie, create variables names Time1, Time2, etc...you'll need to use the eval function:
for aa = 1:38
eval(['Time' num2str(aa) '= dataCOMB{1,1}{1,aa}(1:1024,1);']);
end
Many people do not like recommending the eval function. Others wouldn't recommend moving all of your data out of a data structure and into their own independently-named variables. So, to address these two criticisms, a better alternative might be to pull your data out of your complicated data structure and to put it into a simpler array:
Time_Array = zeros(1024,38);
for aa = 1:38
Time_Array(:,aa) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
Or, if you don't like that because you really like the names Time1, Time2, etc, you could create them as fields to a data structure:
Time_Data = [];
for aa = 1:38
fieldname = ['Time' num2str(aa)];
Time_Data.(fieldname) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
And, in response to a comment below by the original post, this method can be extended to further unpack the data:
Time_Data = [];
count = 0;
for z = 1:2;
for aa = 1:38
count = count+1;
fieldname = ['Time' num2str(count)];
Time_Data.(fieldname) = dataCOMB{1,z}{1,aa}(1:1024,1);
end
end

How to use cell arrays in Matlab?

I am a beginner at using Matlab and came across cell arrays but I am not sure how to use indexing for it.
I have created a cell array of 5 rows and 3 cols by doing the following:
A = cell(5,3);
Now is it possible to go through the cell array by row first and then col like how a nested for loop for a normal array?
for i=1:5
for j=1:3
A{i,j} = {"random"} //random numbers/ string etc
end
end
With cell arrays you have two methods of indexing namely parenthesis (i.e. (...)) and braces (i.e. {...}).
Lets create a cell array to use for examples:
A = {3, 9, 'a';
'B', [2,4], 0};
Indexing using paranthesis returns a portion of the cell array AS A CELL ARRAY. For example
A(:,3)
returns a 2-by-1 cell array
ans =
'a'
0
Indexing using braces return the CONTENTS of that cell, for example
A{1,3}
returns a single character
ans =
a
You can use parenthesis to return a single cell as well but it will still be a cell. You can also use braces to return multiple cells but these return as comma separated lists, which is a bit more advanced.
When assigning to a cell, very similar concepts apply. If you're assigning using parenthesis, then you must assign a cell matrix of the appropriate size:
A(:,1) = {1,1}
if you assign a single value using parenthesis, then you must put it in a cell (i.e. A(1) = 2 will give you an error, so you must do A(1) = {2}). So it's better to use braces as then you are directly affecting the contents of the cell. So it is correct to go
A{1} = 2
this is equivalent to A(1) = {2}. Note that A{1} = {2}, which is what you've done, will not give a error but what is does is nests a cell within your cell which is unlikely what you were after.
Lastly, if you have an matrix inside one of your cells, then Matlab allows you to index directly into that matrix like so:
A{2,2}(1)
ans =
3
for example:
for i=1:5
for j=1:3
A{i,j} = rand(3)
end
end
should work perfectly fine
just skip the { } on the right side of the =

Strcat cell array and array

I have a cell array with strings and a numeric array in Matlab. I want every entry of the cell array to be concatenated with the number from the corresponding position of the array. I think that it can be easily solved using cellfun, but I failed to get it to work.
To clarify, here is an example:
c = {'121' '324' '456' '453' '321'};
array = 1:5
I would like to get:
c = {'1121' '2324' '3456' '4453' '5321'}
A special version of sprintf that outputs directly to a cell array is called sprintfc:
>> C = sprintfc('%d%d',[array(:) str2double(c(:))]).'
C =
'1121' '2324' '3456' '4453' '5321'
It is also a bit different in the way it handles array inputs, by preserving the shape.
You're correct, you can use cellfun – you just need to convert the array to a cell array as well using num2cell. Assuming array is a vector of integers:
c = {'121' '324' '456' '453' '321'};
array = 1:5;
c2 = cellfun(#(c,x)[int2str(x) c],c,num2cell(array),'UniformOutput',false)
which returns
c2 =
'1121' '2324' '3456' '4453' '5321'
In your case, you can also accomplish the same thing just using cell2mat and mat2cell:
c2 = mat2cell([int2str(array(:)) cell2mat(c.')],ones(1,length(array))).'
Another one-liner, this one without undocumented functions (with thanks to #chappjc for showing me the "format" input to num2str):
strcat(num2str(array(:),'%-d'),c(:)).'

Resources