Convert structure array to matrix - matlab

I am trying to convert a structure array to a matrix. Each field of the structure stores a vector that can reach up to 520000 rows. There can be up to 20 fields in a single structure array, but number of rows is the same across the fields.
As a down scaled example consider the structure s, where each field is an integer:
s=struct('a',1,'b',2);
s(2)=struct('a',3,'b',4);
s=s';
In the desired output, each field will correspond to a column. a values will be in the first column, while b values will be in the second:
desiredOutput = [1 2; 3 4];
I have approached this in an indirect way:
cell2mat(struct2cell(s))'
However, this involves two transformations which i find unnecessary due to the well behaved nature of my structure.
I have also approached this using a for loop:
fields = fieldnames(s);
nrows = size(s,1);
ncols = numel(fields);
desiredOutput = nan(nrows,ncols);
for jj=1:ncols
desiredOutput(:,jj) = [s.(fields{fields(jj)})]';
end
I hoped to find a struct2mat function but it does not exist. Is there a simpler way to accomplish this task that I am not aware of?

I had something similar to this written out. So, if you don't mind, I will 'kinda' copy that out over here.
data(1,1).val = 1;
data(1,2).val = 2;
data(2,1).val = 3;
data(2,2).val = 4;
This gives a 2x2 struct with field val.
A = reshape([data.val],size(data))
Now, A looks like this [ 1 2 : 3 4]
A =
1 2
3 4
Does that help?

Related

Matlab - Concatenating non-scalar nested structures with empty fields without losing proper indexing

In Matlab, is there a way to concatenate a non-scalar structure without losing the empty fields? This is interfering with my ability to index within the structure.
I would prefer not to populate all of my "y" fields with NaN for memory management reasons, but I can do this if it is the only work around.
"code" is always fully populated and has no empty cells. "y" could be fully populated but usually is not.
I am providing a quick example: simplified structure (it is really tens of thousands of entries with 50+ fields)
% create example structure
x = struct('y',{1 [] 3 4},'code', {{'a'}, {'b'}, {'c'}, {'b'}});
% concatenate
out = [x.y];
% find indices with code 'b'
ind = find(strcmpi([x.code], 'b'));
% desired output
outSub = out(ind)
I would expect out to yield:
out = [1 NaN 3 4]
Instead I get:
out = [1 3 4]
When trying to use code to create an index to find the values in out that match the desired code value, this obviously does not work.
Error: Index exceeds the number of array elements (3).
The desired output would yield:
out = [2 4];
outSub = [NaN 4]
I am fully open to indexing in a different way as well.
Using the comment above, here is the final solution:
% create example structure
x = struct('y',{1 [] 3 4},'code', {{'a'}, {'b'}, {'c'}, {'b'}});
% concatenate
out = {x.y};
% find indices with code 'b'
ind = find(strcmpi([x.code], 'b'));
% desired output - cell array
outSubCell = out(ind);
% substitute [] for NaN
outSubCell(cellfun('isempty',outSubCell)) = {NaN};
% convert output to double array
outSub = cell2mat(outSubCell)

Perform an operation on indexed/grouped elements of an array in Matlab [duplicate]

I'm working in Matlab.
I have a two-dimensional matrix with two columns. Lets consider elements in the first column as labels. Labels may be repeated.
How to multiply all elements in the second column for every label?
Example:
matrix = [1,3,3,1,5; 2,3,7,8,3]'
I need to get:
a = [1,3,5; 16,21,3]'
Can you help me with doing it without for-while cycles?
I would use accumarray. The preprocessing with unique assigns integer indices 1:n to the values in the first row, which allow accumarray to work without creating unnecessary bins for 2 and 4. It also enables the support for negative numbers and floats.
[ulable,~,uindex]=unique(matrix(:,1))
r=accumarray(uindex,matrix(:,2),[],#prod)
r=[ulable,r]
/You can also use splitapply:
[ulable,~,uindex]=unique(matrix(:,1))
r=splitapply(#prod,matrix(:,2),uindex)
r=[ulable,r]
You can do it without loops using accumarray and the prod function:
clear
clc
matrix = [1,3,3,1,5; 2,3,7,8,3]';
A = unique(matrix,'rows');
group = A(:,1);
data = A(:,2);
indices = [group ones(size(group))];
prods = accumarray(indices, data,[],#prod); %// As mentionned by #Daniel. My previous answer had a function handle but there is no need for that here since prod is already defined in Matlab.
a = nonzeros(prods)
Out = [unique(group) a]
Out =
1 16
3 21
5 3
Check Lauren blog's post here, accumarray is quite interesting and powerful!
Try something like this, I'm sure it can be improved...
unValues = unique(matrix(:,1));
bb = ones(size(unValues));
for ii = 1:length(unValues)
bb(ii) = bb(ii)*prod(matrix(matrix(:, 1) == unValues(ii), 2));
end
a = [unValues bb];

Create a matrix from variables in a data structure

I have a data structure which contains 1520 values. Is it possible to create a matrix using a for loop instead of writing out the matrix manually? The data points are named U_Velocity1 to U_Velocity1520. I'm trying to make a 18x40 matrix where the first column is made from values of U_Velocity1 to 18 and the seconds column is made from the values of U_Velocity19 to 76 and so on. Regards Jer
Considering the following example:
s.a1 = 1;
s.a2 = 3;
s.a3 = 5;
s.a4 = 10;
arr = reshape(struct2array(s),2,2)
arr =
1 5
3 10
Just replace the numbers and variables with your code.

Delete Empty Matrices in Multidimensional Array - MATLAB

I am looking for a way to delete empty matrices within a multidimensional array in MATLAB.
For example, I have a 4-D array such as:
N = 5;
Arr = zeros(2,2,4,N);
Lets assume only N = 2 and N = 4 have values (i.e the four 2x2 matrices in N = 1, 3 and 5 are zeros), how can I create another multidimensional array ArrFin(2,2,4,2) such that
ArrFin(2,2,4,1) = Arr(2,2,4,2);
ArrFin(2,2,4,2) = Arr(2,2,4,4);
I have tried to make the question quite general so that others can benefit from it as well but if I am not making much sense let me know.
Thanks in advance :)
Figured out quite a neat way to do it:
ArrFin = Arr(:,:,:,any(any(any(Arr,3))));
This picks out the non zero matrices and saves them into ArrFin.
Code
%%// Create data
Arr= rand(2,2,4,5);
Arr(:,:,:,[1 3 5]) = 0;
%%// Get new reduced matrix and check for its size
ArrFin = Arr(:,:,:,find(sum(reshape(sum(Arr,3),size(Arr,3),size(Arr,4)),1)));
size_check = size(ArrFin)
Output
size_check =
2 2 4 2

locating common elements in 2D arrays

I have two very long 2D lists called "first_data*" and "second_data", and I would like to locate the elements that are equal and place them in the list "final_data". I have a MWE here:
first_data = [1 2; 3 4]';
second_data = [1 2; 9 4]';
final = [];
for i=1:length(first_data(:, 1))
for j=1:length(second_data(:, 1))
if(first_data(i, 2) == second_data(j, 2))
final = [final first_data(i, 1)];
end
end
end
This gives me 2, as desired. This works, but it is very computationally intensive for very large data sets. Is there a more efficient way to write the above code?
ismember will allow you to do what you want.
%# identify the rows in first_data's second column
%# that occur in second_data's second column
goodIdx = ismember(first_data(:,2),second_data(:,2));
%# return the corresponding values of first_data's first column
final = first_data(goodIdx,1);
Try this code:
first_data = [1 2; 3 4]';
second_data = [1 2; 9 4]';
diff_data=first_data-second_data;
Ind=find(diff_data==0);
final=first_data(Ind);
use:
[c, ia, ib] = intersect(first_data(:, 2), second_data(:, 2));
final = second_data(ib,1);
note: I haven't tested this, but it should work (at least up to row/column mixups)
So your two datasets can be completely described by the following tuples?
"first_data" described by (i,j,data_1) - which indicates that the value data_1 is at row i, column j
"second_data" described by (i,j,data_2)
And you want to find such tuples that are equal?
Convert "first_data", and "second_data" to sets using a Bloom Filter
Perform set intersection using the Bloom Filter representation of "first_data" and "second_data" and obtain essentially constant time set intersection using the bitwise AND of the two representations.