Store big structure in Matlab - arrays

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

Related

Updating a struct with new values in a for loop

My image array: C_filled = 256x256x3270
What I would like to do is calculate the centroids of each image, and store each centroid corresponding to each 'slice'/image into an array. However, when I try to update the array, like a regular array, I get this error:
"Undefined operator '+' for input arguments of type 'struct'."
I have the following code:
for i=1:3270;
cen(i) = regionprops(C_filled(:,:,i),'centroid');
centroids = cat(1, cen.Centroid);% convert the cen struct into a regular array.
cen(i+1) = cen(i) + 1; <- this is the problem line
end
How can I update the array to store each new centroid?
Thanks in advance.
That's because the output of regionprops (i.e. cen(i)) is a structure, to which you try to add the value 1. But since you try to add the value to the structure and not one of its field, it fails.
Assuming that each image can contain multiple objects (and therefore centroids), it would be best (I think) to store their coordinates into a cell array in which each cell can be of a different size, contrary to a numeric array. If you have the exact same number of objects in each image, then you could use a numeric array.
If we look at the "cell array" option with code:
%// Initialize cell array to store centroid coordinates (1st row) and their number (2nd row)
centroids_cell = cell(2,3270);
for i=1:3270;
%// No need to index cen...saves memory
cen = regionprops(C_filled(:,:,i),'centroid');
centroids_cell{1,i} = cat(1,cen.Centroid);
centroids_cell{2,i} = numel(cen.Centroid);
end
and that's it. You can access the centroid coordinates of any image using this notation:centroids_cell{some index}.

Extract specific values from cell based on array in MATLAB

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

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

Accessing data in a nested structure

Okay so I've found a better way of accessing my files but I'm still a bit stuck.
My code so far:
clc % clear window
clear %clear workspace
numfiles = 21;
data = cell(1, numfiles);
obsdata = dir('*.mat');
numfiles = length(obsdata);
data = cell(1, numfiles);
for k = 1:numfiles
data{k} = load(obsdata(k).name);
end
This sorts my data out.
There are 21 cells that contains the J6 - files as shown (the list of the files can be seen on the left):
Clicking each cell brings me to a structure:
Each of which contains data that I want to access.
I'm unsure as to how to go about writing my code so that I can store the data in the last part into two arrays (wavelength and intensity)
Try this. I used deal to copy out each of the obsdata.name's into a cell array called names. (It's probably a poor choice of name for a variable since you already have one called name, but anyway...)
obsdata = dir('*.mat');
numfiles = length(obsdata);
data = cell(1, numfiles);
names = cell(1,numfiles);
names = cell(1,numfiles);
[names{:}] = deal(obsdata.name);
for k = 1:numfiles
data{k} = load(names{k})
end
It'd help to hear a little bit more about how you want to store the data, but generally the work will be done inside the loop you use to load the files. A good starting point might be to get the data out of structs and into cell arrays:
for k = 1:numfiles
data{k} = struct2cell(load(obsdata(k).name));
end
I believe (it's been a while, and I don't have access to matlab anymore) that each of the 21 cells will now contain a cell array, storing the matrices you're interested in. Perhaps this is enough? From this point I think you can access data like this:
data{file_num}{struct_field_num}(x,y)
where x and y are the indices within the matrices that used to be stored as fields in a struct.
If you want to concatenate each of these matrices so that you get 21 cells, each with a single mx2 matrix, you can modify the loop:
for k = 1:numfiles
tmp = load(obsdata(k).name);
data{k} = vertcat(tmp{:});
end
With more information about how you want to structure the data we can refine the answer.

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 =

Resources