Matlab -- Copy Structure Array without For Loop - matlab

I have a fairly simple question in Matlab. I want to copy n items of structure array (sumRT.P) to a matrix (m). In C, I would just use a for loop, like this:
for i = 1:n
m(i) = sumRT(i).P;
end
But I bet there's a simpler way to copy an array in Matlab (that's the whole point of language right?). I tried this:
m = sumRT(1:n).P;
But this just copies the first item in sumRT.P to m, resulting in a 1 X 1 matrix. Note, if I type, sumRT(2).P for example, I can see the second item. Same for any number up to n. Why is this wrong and how do I fix it?

It depends on the data types in your structure array. If they are types of variables, or if they are variables of the same size in arrays of different dimensions, then you can't put them into an array, but you can make them into a cell:
m={sumRT(1:n).P}
and cells are pretty simple to deal with, so this oughtn't be a big problem.
If they are all scalar numerical values, you can create a matrix:
m=cell2mat({sumRT(1:n).P})

Try the following:
m = squeeze(cell2mat(struct2cell(sumRT(1:n))));
This converts the struct array to a cell array, and then to a (numeric) array, and then squeezes it by remoiving singleton dimensions.
Example:
>> sumRT(1).P = 10; sumRT(2).P = 20; sumRT(3).P = 30;
>> n = 2; %// copy first two elements only
>> m = squeeze(cell2mat(struct2cell(sumRT(1:n))))
m =
10
20

Related

Extracting field from cell array of structure in matlab

I have a cell array (let's say size 10) where each cell is a structure with the same fields. Let's say they all have a field name x.
Is there a way to retreive in a vector the value of the field x for all the structure in the cell array? I would expect the function to return a vector of size 10 with in position 1, the value of the field x of the structure in cell 1 etc etc...
EDIT 1:
The structure in the cell array have 1 field which is the same for all but some others which are different.
First convert your cell array of structures, c, (with identical field names in the same order) to a structure array:
c = cell2mat(c)
Then, depending on the data types and sizes of the elements of the field, you may be able to use
[c.x]
to extract your vector of field x values in the "standard" way.
It is also possible that you can skip the conversion step and use cellfun(#(e)e.x, c) to do the extraction in one go.
The below code creates a cell array of structures, and extracts field 'x' of each structure to a vector v.
%create a cell array of structures
s1.a = 'hello';
s1.x = 1;
s2.a = 'world';
s2.x = 2;
c{1} = s1;
c{2} = s2;
v = zeros(1,2);
%extract to vector
for idx=1:size(c,2)
v(1,idx) = c{idx}.x;
end
Let's say you have
c = {s1, s2, s3, ...., sn};
where common field is 'field_1', then you have two options
Use cell2mat.
cc = cell2mat(c); % which converts your cell array of structs into an array of structs
value = [cc.field_1]; % if values are number
or
value = {cc.field_1}; % if values are characters, for example
Another option is to use cellfun.
If the field values are characters, you should set "UniformOutput" to "false"
value = cellfun(#(x) x.field_1, c, 'UniformOutput', false)
The first option is better. Also, try to avoid using cell/cellfun/arrayfun whenever you can, vectors are way faster and even a plain for loop is more effecient

Create matrix of matrix by loading data "MATLAB"

I want make a vector of matrix with loading data of text file.
I am using cat.
n : number of matrices.
p : number of columns of matrices.
every matrix has 4 row.
for example I have 1200 numbers in one text file and p is 3, so n=100.
How can make it?!
This is what I tried to do:
X = cat(n,[1...p; ; ; ],...,[ ; ; ; ]);
The description is a bit vague, but here is what I would recommend:
Read all the data into matlab (It seems like you know how to do this)
Put everything in one big matrix or vector
Only after putting everything together, use the reshape command
In your case you may want to do something like this for step 3:
raw = rand(1200,1); %Assuming your data looks something like this
X = reshape(raw,[],4,3);
For 1200 values this will give you a 100x4x3 answer. Just make sure it is a nice multiple of 4x3 if you apply reshape like this.
Update
Apparently this was the variation the asker was looking for, a 4x3x100 matrix:
X =reshape(r,4,3,100)
If you know the number of matrices (n), you can store it into a cell array like this
myCellArray = cell(n,1);
for it = 1:n
myCellArray{it} = (...) %Load matrix whatever how you do it (Load, fread,...)
end
or just by using dynamic allocation, but not really efficient,
myArray = [];
myArray = [myArray newLoadArray];

Mean value of multiple columns

I have searched a lot to find the solution, but nothing really works for me I think.
I have n data files containing two columns each (imported using uigetfile). To extract the data, I use a for loop like this:
for i=1:n
data{i}=load(filename{i});
x{i}=data{i}(:,1);
y{i}=data{i}(:,2);
end
Now, I want to get the mean value for each row of all the (let's say) x-values. E.g.:
x{1} = [1,4,7,8]
x{2} = [1,2,6,9]
Then I want something like
x_mean = [1,3,6.5,8.5]
I have tried (where k is number of rows)
for i=1:n
data{i}=load(filename{i});
x{i}=data{i}(:,1);
y{i}=data{i}(:,2);
j=1:k
x_mean=sum(x{i}(j))/n
end
But I can't use multiple counters in a for loop (as I understand). Moreover, I don't use mean as I don't see how I can use it in this case.
If someone could help me, it would be great!
You can capture the contents of each numeric array in the cell x into a new numeric array x_num like so:
x_num = [x{:}]
Computing the mean is then as simple as
mean_x = mean( [x{:}] )
For your example, that gives you the mean of all numbers in all arrays in x, which will therefore be a scalar.
If you want to compute the mean of all the rows (column-wise mean), as your example would indicate), you have to concatenate your arrays vertically, which you can do with cat:
mean_x_columnwise = mean( cat(1,x{:}) )
If you want to take the mean over all the columns (row-wise mean), you should only have to tell mean that you are looking at a different dimension:
mean_x_rowwise = mean( cat(1,x{:}), 2)

How to change row number in a FOR loop... (MATLAB newbie)

I have a set of data that is <106x25 double> but this is inside a struct and I want to extract the data into a matrix. I figured a simple FOR loop would accomplish this but I have hit a road block quite quickly in my MATLAB knowledge.
This is the only piece of code I have, but I just don't know enough about MATLAB to get this simple bit of code working:
>> x = zeros(106,25); for i = 1:106, x(i,:) = [s(i).surveydata]; end
??? Subscripted assignment dimension mismatch.
's' is a very very large file (in excess of 800MB), it is a <1 x 106 struct>. Suffice it to say, I just need to access a small portion of this which is s.surveydata where most rows are a <1 x 25 double> (a row vector IIRC) and some of them are empty and solely return a [].
s.surveydata obviously returns the results for all of the surveydata contained where s(106).surveydata would return the result for the last row. I therefore need to grab s(1:106).surveydata and put it into a matrix x. Is creating the matrix first by using x = zeros(106,25) incorrect in this situation?
Cheers and thanks for your time!
Ryan
The easiest, cleanest, and fastest way to write all the survey data into an array is to directly catenate it, using CAT:
x = cat(1,s.surveydata);
EDIT: note that if any surveydata is empty, x will have fewer rows than s has elements. If you need x to have the same amount of rows as s has elements, you can do the following:
%# find which entries in s have data
%# note that for the x above, hasData(k) contains the
%# element number in s that the k-th row of x came from
hasData = find(arrayfun(#(x)~isempty(x.surveydata),s));
%# initialize x to NaN, so as to not confuse the
%# real data with missing data entries. The call
%# to hasData when indexing makes this robust to an
%# empty first entry in s
x = NaN(length(s),length(s(hasData(1)).surveydata);
%# fill in only the rows of x that contain data
x(hasData,:) = cat(1,s(hasData).surveydata);
No, creating an array of zeroes is not incorrect. In fact it's a good idea. You don't have to declare variables in Matlab before using them, but for loops, pre-allocating has speed benefits.
x = zeros(size(s), size(s(1)));
for i = 1:106
if ~isempty(s(i).surveydata)
x(i, :) = s(i).surveydata;
end
end
Should accomplish what you want.
EDIT: Since OP indicated that some rows are empty, I accounted for that like he said.
what about this?
what s is?
if s(i).surveydata is scalar:
x = zeros(106,25);
for i = 1:106
x(i,1) = [s(i).surveydata];
end
I am guessing that is what you want tough it is not clear at all :
if s(i).surveydata is row vector:
x = zeros(106,25);
for i = 1:106
x(i,:) = [s(i).surveydata];
end
if s(i).surveydata is column vector:
x = zeros(106,25);
for i = 1:106
x(i,:) = [s(i).surveydata]';
end

Retrieving element index in spfun, cellfun, arrayfun, etc. in MATLAB

Is there any way to retrieve the index of the element on which a function called by cellfun, arrayfun or spfun acts? (i.e. retrieve the index of the element within the scope of the function).
For the sake of simplicity, imagine I have the following toy example:
S = spdiags([1:4]',0,4,4)
f = spfun(#(x) 2*x,S)
which builds a 4x4 sparse diagonal matrix and then multiplies each element by 2.
And say that now, instead of multiplying each element by the constant number 2, I would like to multiply it by the index the element has in the original matrix, i.e. assuming that linear_index holds the index for each element, it would be something like this:
S = spdiags([1:4]',0,4,4)
f = spfun(#(x) linear_index*x,S)
However, note the code above does not work (linear_index is undeclared).
This question is partially motivated by the fact that blocproc gives you access to block_struct.location, which one could argue references the location (~index) of the current element within the full object (an image in this case):
block_struct.location: A two-element vector, [row col], that specifies
the position of the first pixel (minimum-row, minimum-column) of the
block data in the input image.
No, but you can supply the linear index as extra argument.
Both cellfun and arrayfun accept multiple input arrays. Thus, with e.g. arrayfun, you can write
a = [1 1 2 2];
lin_idx = 1:4;
out = arrayfun(#(x,y)x*y,a,lin_idx);
This doesn't work with spfun, unfortunately, since it only accepts a single input (the sparse array).
You can possibly use arrayfun instead, like so:
S = spdiags([1:4]',0,4,4);
lin_idx = find(S);
out = spones(S);
out(lin_idx) = arrayfun(#(x,y)x*y,full(S(lin_idx)),lin_idx);
%# or
out(lin_idx) = S(lin_idx) .* lin_idx;
Note that the call to full won't get you into memory trouble, since S(lin_idx) is 0% sparse.
You can create a sparse matrix with linear_index filling instead of values.
Create A:
A(find(S))=find(S)
Then use A and S without spfun, e.g.: A.*S. This runs very fast.
It's simple. Just make a cell like:
C = num2cell(1:length(S));
then:
out=arrayfun(#(x,c) c*x,S,C)