Preallocating a structure with variables of different names, size and type - matlab

I am going to use an algorithm in a for loop as an iteration loop. I know that some of the calculations can be done once and the their results can be used as necessary inputs for the algorithm in the for loop so in this way there is no need to calculate the same things in each iteration. To do so, I calculate them once and put them in a structure.
I use structure since I have many variables to be kept to be used in the for loop and their name and size are different. I put them in the structure with the same name for example:
out.A = A;
out.myvector = myvector;
out.s = s;
out.Hx_l = Hx_l;
and so on. some of them are matrices, some of them cubes or variables with a forth dimension and some of them are cells.
Is there any way to preallocate this kind of structure?

You could initialise the structure the following way:
out = struct('A',[],'myvector',[],'s',[],'Hx',[]);
When you assign the variables afterwards, the structure fields will be already created. Usually the contents are not initialised upfront. Quoting Loren:
How important is it to initialize the contents of the struct. Of
course it depends on your specifics, but since each field is its own
MATLAB array, there is not necessarily a need to initialize them all
up front. The key however is to try to not grow either the struct
itself or any of its contents incrementally.

Related

How to loop through multiple structures and perform the same operations [Matlab]

I am trying to loop through multiple structures at once, extract variables of interest, and combine them into a single cell array. The problem: all of the variables have the same names. I have a working pseudocode--here it is:
Let's say I load i structures in my workspace. Now I want to loop through each structure, and extract time and position data from each structure.
First, I load my structures. Something like...
data_1
data_2
data_3
Then, I create appropriately sized cell arrays.
time{i,:} = zeros(size(structures));
position{i,:} = zeros(size(structures));
Finally, I loop through my structures to extract cell arrays and create a single array.
for i = 1:size(structures)
time_i= data_i.numbers.time;
position_i= data_i.numbers.position;
time {i,:} = time_i;
position{i,:} = position_i;
end
I want to end with a cell array containing a concatenation of all the variables in a single cell structure.
Could you please help convert my pseudo code/ideas into a script, or point me to resources that might help?
Thanks!
You're likely going to be better off loading your data internal to the loop and storing it into a cell or structure rather than trying to deal with iteratively named variables in your workspace. eval is, in nearly all cases, a significant code smell, not least of which because MATLAB's JIT compiler ignores eval statements so you get none of the engine's optimizations. eval statements are also difficult to parse, debug, and maintain.
An example of a stronger approach:
for ii = 1:nfiles
tmp = load(thefilenames{ii}); % Or use output of dir
trialstr = sprintf('trial_%u', ii); % Generate trial string
data.(trialstr).time = tmp.numbers.time;
data.(trialstr).position = tmp.numbers.position;
end
Which leaves you with a final data structure of:
data
trial_n
time
position
Which is far easier to iterate through later.
My final script for anyone interested:
for i = 1:4 %for 4 structures that I am looping through
eval(['time_',num2str(i),'= data_',num2str(i),'.numbers.time;']);
eval(['position_',num2str(i),'= data_',num2str(i),'.numbers.position;']);
%concatenate data into a single cell array here
time{i} = {eval(['time_',num2str(i)])};
position{i} = {eval(['position_',num2str(i)])};
end
...
eval(['time_',num2str(i),'= data_',num2str(i),'.numbers.time;'])
eval(['position_',num2str(i),'= data_',num2str(i),'.numbers.position;'])
...

How to do preallocation in storing field variables in matlab

I am storing the field variables calculated in a for loop in a vector by appending the values, However I would like to preallocate first for performance. I tried to vectorize this operation but it does not give me what I would like to accomplish. I have put the example of the operation below. How do I do the preallocation in this? For speed.
j=('load raw.mat');
var=fields(j);
val_mat=[];
kk=fieldnames(j);
for i=(length(kk)-Var_no)+1:Var_no+(length(kk)-Var_no)
val_mat=[val_mat j.(var{i})];
end
Based on your code it looks like you are trying to grab all variables stored in raw.mat and concatenate them. To do this, you can replace the loop with struct2cell to convert all field values to a cell array of values and then use cat to concatenate them
data = load('raw.mat');
values = struct2cell(data);
val_mat = cat(2, values{:});
Since we have removed the loop, there is no need to pre-allocate.
I've also taken the liberty to rewrite your code as valid MATLAB code.

error in array of struct matlab

I want to train data on various labels using svm and want svm model as array of struct. I am doing like this but getting the error:
Subscripted assignment between dissimilar structures.
Please help me out
model = repmat(struct(),size);
for i=1:size
model(i) = svmtrain(train_data,labels(:,i),'Options', options);
end
A structure array in MATLAB can only contain structures with identical fields. By first creating an array of empty structures1 and then trying to fill it with SVMStruct structures, you try to create a mixed array with some empty structures, and some SVMStruct structures. This is not possible, thus MATLAB complains about "dissimilar structures" (not-equal structures: empty vs. SVMStruct).
To allocate an array of structs, you will have to specify all fields during initialization and fill them all with initial values - which is rather inconvenient in this case. A very simple alternative is to drop this initialization, and run your loop the other way around2,3:
for ii=sizeOfLabels:-1:1
model(ii) = svmtrain(train_data,labels(:,ii),'Options', options);
end
That way, for ii=sizeOfLabels, e.g. ii=100, MATLAB will call model(100)=..., while model doesn't exist yet. It will then allocate all space needed for 100 SVMStructs and fill the first 99 instances with empty values. That way you pre-allocate the memory, without having to worry about initializing the values.
1Note: if e.g. size=5, calling repmat(struct(),size) will create a 5-by-5 matrix of empty structs. To create a 1-by-5 array of structs, call repmat(struct(),1,size).
2Don't use size as a variable name, as this is a function. If you do that, you can't use the size function anymore.
3i and j denote the imaginary unit in MATLAB. Using them as a variable slows the code down and is error-prone. Use e.g. k or ii for loops instead.

Matlab: Matrix of ClassificationKNN class objects

For classification I'm building a number of models for a classifier in MATLAB. I use the class ClassificationKNN for this.
I would very much like to store multiple models (or objects of this class) inside a matrix.
Normally you could access and create matrices inside a matrix with the curly braces ({}).
My loop looks like this:
models = []
for i = 1:length(x)
models = [models, {ClassificationKNN.fit(x,y)}]
end
Unfortunately this returns a matrix models of size (1,3) but all cells are empty which means the models are lost...
How can I make sure every model is stored in a matrix? I need to do this because I need all models later in my calculations and the position in the matrix is important...
Any ideas?
You want a cell array of models, right? It sure looks that way, if that will work try this:
models = {}
for ii = 1:length(x)
models = [models, {ClassificationKNN.fit(x,y)}]
end
Also, you loop through calling ClassificationKNN.fit(x,y) with the same arguments every time, is this just a test, or pseudo-code for an example. Like the comment says, it's best to preallocate like:
models = cell(length(x),1);
for ii = 1:length(x)
models{ii} = ClassificationKNN.fit(x,y);
end
But, either way is likely fine.
Thanks to macduffs post I finally figured out what was going on. Whilest reading his proposition I realised that that indeed should be the correct way if getting a cell array of objects.
After trying it, the array again seemed empty when opening it in the variable editor. I tried calling the first cell in the array to see if it was indeed empty and it was not. It returned the object I had stored in it. This means the question was answered.
I then reverted back to my own method to see if that worked as well and it did. When calling a cell it also returned an object.
Bottom line:
Do not trust the variable editor ^^.

preallocate structure matlab

I am thinking of creating a structure like Q.Q.Q.W(1,12).x1...Q.Q.Q.W(1,12).x40 so I have 12 fields for W and for each of them 40 pairs: field-value inside (cells, strings, integers). I want to preallocate this structure. In this case I already have an existing structure like this but with data, and depending on conditions I either modify these data and save to my new structure, or just go further with empty preallocated structure.
So I have to obtain a structure preallocated of dimensions exactly like my structure with datas, but thi sone has to be empty. How to do it without entering all these 12 times 50 names and so ?
would be just like s = struct(obj) from help, but should not contain the content of obj, but be empty.
help please if you have any idea
Indeed, it does not seem to be the best of choices on how to store your data -- the resulting structure wouldn't be the easiest thing in the world to manipulate.
Nevertheless, if your customer/client/whomever expects you to return the same data structure as you were given, it is a legitimate use case.
So, you can do something like
for ii = 1:40
Q.Q.Q.W(12).(['x' num2str(ii)]) = [];
end
to create the initial structure.
I didn't quite understand what you want to fill the structure with initially -- can you clarify this a bit?