Data from array struct in corresponding shape - arrays

Say, we have an array of structs
data = struct('position',[]);
data(1,1).position = 11;
data(1,2).position = 12;
data(2,1).position = 21;
data(2,2).position = 22;
I learned that to get the entries from a field from all structs in the array, we can use
>> [data.position]
ans =
11 21 12 22
But this gives the data in a row. How can we get it in the original shape of the array, without looping the array in MCode?
Desired output:
position =
11 12
21 22

Use reshape. This will restructure an input vector / matrix into another vector / matrix of a desired shape. Specifically, you can specify the dimensions of data into reshape as well as the row vector produced by [data.position] and it'll reshape the vector with the right dimensions for you.
data = struct('position',[]);
data(1,1).position = 11;
data(1,2).position = 12;
data(2,1).position = 21;
data(2,2).position = 22;
position = reshape([data.position], size(data))
position =
11 12
21 22
Note that the elements are shaped in column-major format so the values are stacked column-wise. As you can see, the first two elements become the first column of the output matrix, while the last two elements become the second column of the output matrix.

If you are working with empty entries, you can use struct2cell to convert the struct data into cell array that enables us to store empty entries as empty cells -
data_cell = permute(struct2cell(data),[2 3 1])
out = data_cell(:,:,strcmp(fieldnames(data),'position'))
So, if you have something like this with the (2,2) missing -
data = struct('position',[]);
data(1,1).position = 11;
data(1,2).position = 12;
data(2,1).position = 21;
You would have -
out =
[11] [12]
[21] []
Based on #CitizenInsane's nice observation and which might be very close to #rayryeng's answer, but one that deals with cell arrays instead of numeric arrays, would be this -
out = reshape({data.position}, size(data))

Related

How to convert strings in a cell array to numerical stand-in values?

In Matlab, I have a cell array of cell arrays created using textscan on a tab-separated data file. Some columns of the data set are strings. Here is an example array, 'data':
data{1,1} = {1; 2; 3; 4; 5};
data{1,2} = {11; 12; 13; 14; 15};
data{1,3} = {'Ringo'; 'Paul'; 'The Beatles'; 'John'; 'George'};
I want to convert the string columns to specific numerical stand-in values (i.e. 'The Beatles' = 1, 'John' = 2, 'Paul' = 3, 'George' = 4, 'Ringo' = 5). Also, it may be important to note that some cells contain more than one "word".
For some context, the entire data set will ultimately be converted from a cell array into one neatly packaged double array (data = cell2mat(data)) for easier manipulation.
The only solution I know is to loop through the string array and use a switch statement:
vec_0 = data{1,3};
for ii = 1:length(vec_0)
switch vec_0{ii}
case 'The Beatles'
vec_f{ii,1} = 1;
case 'John'
vec_f{ii,1} = 2;
case 'Paul'
vec_f{ii,1} = 3;
case 'George'
vec_f{ii,1} = 4;
case 'Ringo'
vec_f{ii,1} = 5;
end
end
% Replace string column with numerical stand-ins
data{1,3} = vec_f;
% Convert cell array to double array
data = cell2mat(data);
Now we have:
data = [1 11 5; 2 12 3; 3 13 1; 4 14 2; 5 15 4];
What is a more optimal way to do this?
If you have a specific mapping of strings to numeric values...
Let's say you have a mapping of strings to numeric values as defined in the following 5-by-2 cell array (one mapping per row):
numMap = {'The Beatles', 1; 'John' , 2; 'Paul' , 3; 'George' , 4; 'Ringo' , 5};
Then you can use ismember to convert the strings to their mapped numeric values and save it back in data like so:
[~, index] = ismember(data{1, 3}, numMap(:, 1));
data{1, 3} = numMap(index, 2);
If you need to generate a mapping of strings to numeric values...
You can generate an array of numerical stand-ins with unique, convert that to a cell array with num2cell, and save it back in data like so:
[uniqueStrings, ~, numIndex] = unique(data{1, 3}, 'stable');
data{1, 3} = num2cell(numIndex);
And uniqueStrings will contain the unique multi-word strings from data{1, 3}.
Converting to a double array:
Once you've chosen one of the above options, you can then convert your sample data to a 5-by-3 double array like so:
data = cell2mat([data{:}]);
data =
1 11 5
2 12 3
3 13 1
4 14 2
5 15 4

Adding an element of an array with respective element of other arrays

I have multiple array, number can be arbitrary. but the size of all array is same. How do i add each element of with respective element of all the arrays and maybe save it in another array
A1 = [1 2 3 4 5 6]
A2 = [1 2 3 4 5 6]
.
.
.
.
final = [1+1+1+... 2+2+2+.... 3+3+3+3.... 4+4+4.... 5+5+5+5... 6+6+6+6...]
As your arrays are all the same length you can just add the arrays forming a new array.
final = A1+A2
This function searches in your workspace looking for all variables containing capital 'A'. The for loop adds all found variables. If there are other variables containing 'A', other restrictions has to be made.
variables = who %# all variable names from workspace
index = strmatch('A',variables) %# indices matching "A"
newarray = 0
for j = 1:numel(index)
tmp = eval(char(variables(index(j)))); %# store variable in tmp
newarray = newarray + tmp; %# sum
end
If you have an unknown number of A's, you can try something like this:
final = 0
i = 1
while exist(['A' num2str(i)]) == 1 % ['A' num2str(i)] constructs the variable name, eval calls it
final = final + eval(['A' num2str(i)]);
i = i + 1;
end
This should work as long as the variables are stored in the workspace, are of the same length and are named A1, A2, A3, ... A9, A10, ...
Let's say you have this structure (as you write in the comments):
main = struct('err',{1:6,5:10,1:6,1:6},'seg_err',{1:6,5:10,1:6,5:10});
you can convert it to matrix:
m = vertcat(main.seg_err);;
And than take the sum in a simple command:
final = sum(m)
which results:
final =
12 16 20 24 28 32
and thanks to #beaker :)

How to convert a character matrix into cell array?

I have 64 characters in a 4*4 matrix.I need to convert it into a cell array such that cell has 4 characters.For eg
Consider A=[TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT]
i need to get a cell array as below
B={[TCTG][CTCT][CGGT][TATA]
[TACA][CTGC][CCAG][AACA]
[CGTC][AACA][AGGC][CAGT]
[GTAT][CCTT][CTTT][GTGT]}
i tried using the mat2cell function but im not able to understand it.please help.
Using a for-loop:
clc
clear
A = 'TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT';
B = cell(4,4);
currentIdx = 0; % Use index to increment by steps of 4 when going through A
for k = 1:16
B{k} = A(currentIdx+1:currentIdx+4);
currentIdx = currentIdx+4;
end
B = B'
B =
'TCTG' 'CTCT' 'CGGT' 'TATA'
'TACA' 'CTGC' 'CCAG' 'AACA'
'CGTC' 'AACA' 'AGGC' 'CAGT'
'GTAT' 'CCTT' 'CTTT' 'GTGT'
You are starting with a 1xN matrix and want to convert it to a 1xN/4 cell array of 1x4 matrices. Your command should then be:
N = length(A);
M = 4;
B = mat2cell(A,1,ones(1,N/M)*M);
The first dimension is the 1, the second dimension is a string of 4's the size of the output cell array. The result:
B =
Columns 1 through 12
'TCTG' 'CTCT' 'CGGT' 'TATA' 'TACA' 'CTGC' 'CCAG' 'AACA' 'CGTC' 'AACA' 'AGGC' 'CAGT'
Columns 13 through 16
'GTAT' 'CCTT' 'CTTT' 'GTGT'
You can use method vec2mat that breaks your input vector to matrix
M = vec2mat(A, numberOfColumns)
(In your case numberOfColumns would be 16) and then use mat2cell. In your case, it would be:
C = mat2cell(M, [1,1,1,1], [4,4,4,4])
It means that all cels will have one row and 4 columns).
Effect of function c = mat2cell(x, [10, 20, 30], [25, 25]) would be:
The image shows why you have to convert vector to matrix. (example from matlab documentation)
You can also (ab)use the very versatile accumarray for this task:
A = 'TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT';
n = 4;
B = accumarray(ceil(1/n:1/n:numel(A)/n).', A(:), [], #(x) {x.'}).'

reshape 2d array to 3d array in matlab /octave

How can I reshape a 2d array to a 3d array with the last column being used as pages?
All data found in array2d should be in pages
example:
array2d=[7,.5,12; ...
1,1,1; ...
1,1,1; ...
4,2,4; ...
2,2,2; ...
2,2,2; ...
3,3,3; ...
3,3,3; ...
3,3,3];
The first page in the array would be
7,.5,12;
1,1,1;
1,1,1;
The second page in the array would be
4,2,4;
2,2,2;
2,2,2;
The third page in the array would be
3,3,3;
3,3,3;
3,3,3;
This is a 9x3 array how can I get it to be a 9x3x? (not sure what this number should be so I placed a question mark as a place holder) multidimensional array?
What I'm trying to get is to have
All the ones would be on one dimension/page all the two's would be another dimension/page etc... –
I tried reshape(array2d,[9,3,1]) and it's still a 9x3
Use permute with reshape -
N = 3; %// Cut after every N rows to form a "new page"
array3d = permute(reshape(array2d,N,size(array2d,1)/N,[]),[1 3 2]) %// output
Assuming that each slice of your matrix is the same in dimensions, we can do this very easily. Let's call the number of rows and columns that each slice would have to be M and N respectively. In your example, this would be M = 3 and N = 3. As such, assuming array2d is of the above form, we can do the following:
M = 3;
N = 3; %// This is also simply the total number of columns we have,
%// so you can do size(array2d, 2);
outMatrix = []; %// Make this empty. We will populate as we go.
%// Figure out how many slices we need
numRows = size(array2d,1) / M;
for k = 1 : numRows
%// Extract the k'th slice
%// Reshape so that it has the proper dimensions
%// of one slice
sliceK = reshape(array2d(array2d == k), M, N);
%// Concatenate in the third dimension
outMatrix = cat(3,outMatrix,sliceK);
end
With your example, we thus get:
>> outMatrix
outMatrix(:,:,1) =
1 1 1
1 1 1
1 1 1
outMatrix(:,:,2) =
2 2 2
2 2 2
2 2 2
outMatrix(:,:,3) =
3 3 3
3 3 3
3 3 3
This method should generalize for any number of rows and columns for each slice, provided that each slice shares the same dimensions.
Your array is already of size 1 in the 3rd dimension (in other words, it is already 9x3x1, to prove this try entering array2d(1,1,1)). If you want to concatenate 2d matrices along the 3rd dimension you can use cat.
For example:
a = [1,2;3,4];
b = [5,6;7,8];
c = cat(3,a,b);
c will be a 2x2x2 matrix.
This piece of code is specific for this example, I hope you will be able to understand how to go for other data samples.
out2 = [];
col = size(array2d,2);
for i = 1:3
temp2 = reshape(array2d(array2d == i),[],col);
out2 = cat(3,out2,temp2);
end

What is the difference between the data stored in a cell and the data stored as double in MATLAB?

I have two variables who look exactly the same to me, but one is <double> and the other is <cell>. In the code it seems that they are converted by cell2mat. I understand it is a question of data storage but I just don't see the difference and the definition of cell and double for this.
Adding to nrz's answer, it is noteworthy that there is an additional memory overhead when storing cell arrays. For instance, consider the following code:
A = 1:5
B = {A}
C = num2cell(A)
whos
which produces the following output:
A =
1 2 3 4 5
B =
[1x5 double]
C =
[1] [2] [3] [4] [5]
Name Size Bytes Class Attributes
A 1x5 40 double
B 1x1 152 cell
C 1x5 600 cell
As you can see from the first line, the basic 1-by-5 vector A of doubles takes 40 bytes in memory (each double takes 8 bytes).
The second line shows that just wrapping A with a single cell to produce B adds extra 112 bytes. That's the overhead of a single cell in MATLAB.
The third line confirms that, because C contains 5 cells and takes (112+8)×5 = 600 bytes.
Arrays and cell arrays are probably the two most commonly used data types in MATLAB.
1D and 2D arrays are matrices just like in mathematics, in linear algebra. But arrays can also be multidimensional (n-dimensional) arrays, also called tensors, MATLAB calls them multidimensional arrays. Further, MATLAB does not make any distinction between scalars and arrays, nor between vectors and other matrices. A scalar is just a 1x1 array in MATLAB, and vectors are Nx1 and 1xN arrays in MATLAB.
Some examples:
MyScalar = 1;
MyHorizVector = [ 1 2 3 ];
MyVertVector = [ 1 2 3 ]';
MyMatrix = [ 1, 2; 3, 4 ];
My4Darray = cat(4, [ 1 2; 3 4], [ 5 6; 7 8 ], [ 9 10; 11 12 ], [ 13 14; 15 16 ]);
class(MyScalar)
ans =
double
class(MyHorizVector)
ans =
double
class(MyVertVector)
ans =
double
class(MyMatrix)
ans =
double
class(My4Darray)
ans =
double
So, the class of all these 5 different arrays is double, as reported by class command. double means the numeric precision used (double-precision).
The cell array is a more abstract concept. A cell array can hold one or more arrays, it can also hold other types of variables that are not arrays. A cell array can also hold other cell arrays which can again hold whatever a cell array can hold. So, cell arrays can also be stored recursively inside one another.
Cell arrays are useful for combining different objects into a single variable that can eg. be passed to a function or handled with cellfun. Each cell array consists of 1 or more cells. Any array can be converted to cell array using { } operators, the result is a 1x1 cell array. There are also mat2cell and num2cell commands available.
MyCellArrayContainingMyScalar = { MyScalar };
MyCellArrayContainingMyHorizVector = { MyHorizVector };
MyCellArrayContainingMyCellArrayContainingMyScalar = { MyCellArrayContainingMyScalar };
All cell arrays created above are 1x1 cell arrays.
class(MyCellArrayContainingMyScalar)
ans =
cell
class(MyCellArrayContainingMyHorizVector)
ans =
cell
class(MyCellArrayContainingMyCellArrayContainingMyScalar)
ans =
cell
But not all cell arrays can be converted into matrices using cell2mat, because a single cell array can hold several different data types that cannot exist in the same array.
These do work:
cell2mat(MyCellArrayContainingMyScalar)
ans =
1
cell2mat(MyCellArrayContainingMyHorizVector)
ans =
1 2 3
But this fails:
cell2mat(MyCellArrayContainingMyCellArrayContainingMyScalar);
Error using cell2mat (line 53)
Cannot support cell arrays containing cell arrays or objects.
But let's try a different kind of a cell array consisting of different arrays:
MyCellArray{1} = [ 1 2 3 ];
MyCellArray{2} = 'This is the 2nd cell of MyCellArray!';
class(MyCellArray)
ans =
cell
This cell array neither cannot be converted to an array by using cell2mat:
cell2mat(MyCellArray)
Error using cell2mat (line 46)
All contents of the input cell array must be of the same data type.
Hope this helps to get an idea.

Resources