Reshape matrix from 3d to 2d keeping specific order - matlab

I would like to resize a matrix under the form let's say 4x3x5, to a 2d matrix of 20x3 but while preserving the order as illustrated below :
The function reshape() does not keep this particular order, how could I achieve this the simplest way possible ?

Let's solve these problems of concatenating and cutting across the third dimension once and for all!
Part I (3D to 2D) : Concatenate along the columns and across the 3rd dim of a 3D array, A to form a 2D array -
reshape(permute(A,[1 3 2]),[],size(A,2))
Part II (2D to 3D) : Cut a 2D array B after every N rows to form 3D slices of a 3D array -
permute(reshape(B,N,size(B,1)/N,[]),[1 3 2])
Sample run -
Part I (3D to 2D)
>> A
A(:,:,1) =
4 1 4 3
8 4 6 4
8 5 6 1
A(:,:,2) =
9 4 4 1
2 2 9 7
1 5 9 3
A(:,:,3) =
4 4 7 7
5 9 6 6
9 3 5 2
>> B = reshape(permute(A,[1 3 2]),[],size(A,2));
>> B
B =
4 1 4 3
8 4 6 4
8 5 6 1
9 4 4 1
2 2 9 7
1 5 9 3
4 4 7 7
5 9 6 6
9 3 5 2
Part II (2D to 3D)
>> N = 3;
>> permute(reshape(B,N,size(B,1)/N,[]),[1 3 2])
ans(:,:,1) =
4 1 4 3
8 4 6 4
8 5 6 1
ans(:,:,2) =
9 4 4 1
2 2 9 7
1 5 9 3
ans(:,:,3) =
4 4 7 7
5 9 6 6
9 3 5 2

Related

Return 2d array from 3d array masked by 2d array

With a 3 dimensional matrix and 2 dimensional boolean mask, I am trying to return all the 3-value sets that correspond to a True in the mask. For example
I have the matrix:
matrix(:,:,1) =
1 2 3
4 5 6
7 8 9
matrix(:,:,2) =
1 2 3
4 5 6
7 8 9
matrix(:,:,3) =
1 2 3
4 5 6
7 8 9
and a mask:
mask =
0 0 0
0 1 1
1 1 1
>> matrix(mask)
ans =
7
5
8
6
9
this indexing seems to only mask the first slice of the 3d matrix. What can I do to return a 2d array with all the specified 3-value pairs?
Though the shape and order are not important, I would like my output to look something like the following, where one dimension of the output corresponds to 3rd dimension of the 3d array.
[7,7,7]
[5,5,5]
[8,8,8]
[6,6,6]
[9,9,9]
You can do this by turning the original 3d array into 2d where each row comes from a vector in the 3rd dimension:
matrix2 = reshape(matrix, [], size(matrix, 3))
matrix2 =
1 1 1
4 4 4
7 7 7
2 2 2
5 5 5
8 8 8
3 3 3
6 6 6
9 9 9
Then use the indices of the 1's in mask as row indices:
vectors = matrix2(find(mask), :)
vectors =
7 7 7
5 5 5
8 8 8
6 6 6
9 9 9
As #LuisMendo mentions in the comments, if mask is a logical array, you don't even need the call to find:
vectors = matrix2(mask, :)
vectors =
7 7 7
5 5 5
8 8 8
6 6 6
9 9 9

MATLAB - generating vector with sequence of values

Given two parameters:
n %number of repetitions per value
k %max value to repeat
I would like to create a vector of size n*k, which is a concatenation of k vectors of size n, such that the i'th vector contains the value i at each coordinate.
Example:
n = 5;
k = 9;
Desired result:
[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9,9,9];
Is there an elegant way to achieve this?
Thanks!
quite a few ways to do it:
method 1:
A=1:k
repelem(A',n,1)'
method 2:
A=1:k
kron(A', ones(n,1))'
method 3:
A=1:k
B=repmat(A, n, 1)
B(:)'
method 4:
A=1:k
B=ones(n,1)*A
B(:)'
Here is an alternative method
A = reshape(mtimes((1:k).',ones(1,n)).',1,n*k)
A =
Columns 1 through 22
1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5
Columns 23 through 44
5 5 5 6 6 6 6 6 7 7 7 7 7 8 8 8 8 8 9 9 9 9
Column 45
9
It multiplies each element by ones n times
>> mtimes((1:k).',ones(1,5)).'
ans =
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
and then reshapes the whole matrix to one vector

How can I store a matrix in a row of another matrix? MATLAB

I have a 3D matrix and I want to store each 2D component of this in the row of another 2D matrix which has many rows as the 3rd dimension of the 3D matrix.
How can I do this?
With permute & reshape -
reshape(permute(A,[3 2 1]),size(A,3),[])
Sample run -
>> A
A(:,:,1) =
7 1 7 5
3 4 8 5
9 4 2 6
A(:,:,2) =
7 7 2 4
7 6 5 6
3 2 9 3
A(:,:,3) =
7 7 5 3
3 9 2 8
5 9 2 3
>> reshape(permute(A,[3 2 1]),size(A,3),[])
ans =
7 1 7 5 3 4 8 5 9 4 2 6
7 7 2 4 7 6 5 6 3 2 9 3
7 7 5 3 3 9 2 8 5 9 2 3
If you don't mind a little indexing madness...
You can build a linear index with the appropriate shape, which applied on the original array will give the desired result:
B = A(bsxfun(#plus, (1:L*M:L*M*N).', reshape(bsxfun(#plus, (0:L:L*M-1).', 0:L-1),1,[])));
Example:
>> A = randi(10,2,3,4)-1; %// example array; size 2x3x4
>> A
A(:,:,1) =
5 3 2
9 8 9
A(:,:,2) =
8 7 4
9 8 6
A(:,:,3) =
3 4 8
0 4 4
A(:,:,4) =
2 8 8
4 6 7
Result:
>> B
B =
5 3 2 9 8 9
8 7 4 9 8 6
3 4 8 0 4 4
2 8 8 4 6 7
That is easily done with MATLABs matrix unrolling syntax:
A=ones(N,M,O);
B=zeros(O,N*M);
for ii=1:size(A,3)
aux=A(:,:,ii); % aux is NxM
B(ii,:)=aux(:); % unroll!
end
(note I called O the thing you call N in your pictures)

repmat, the size of matrix or number of use

I have a matrix for which I extract each column and do repmat function for each of them to build another matrix. Since i I have to do this for a large number of vectors(each column of my first matrix) it takes so long(relative to which I expect). If I do this for the whole matrix and then do something to build them, does it takes less time?
Consider this as an example:
A=[1 4 7;2 5 8;3 6 9]
I want to produce these
A1=[1 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 2 3]
A2=[4 5 6 4 5 6 4 5 6
4 5 6 4 5 6 4 5 6
4 5 6 4 5 6 4 5 6]
A3=[7 8 9 7 8 9 7 8 9
7 8 9 7 8 9 7 8 9
7 8 9 7 8 9 7 8 9]
As an alternative to #thewaywewalk's answer and using kron and repmat:
clear
A=[1 4 7;2 5 8;3 6 9];
B = repmat(kron(A',ones(3,1)),1,3);
A1 = B(1:3,:)
A2 = B(4:6,:)
A3 = B(7:end,:)
Which results in the following:
A1 =
1 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 2 3
A2 =
4 5 6 4 5 6 4 5 6
4 5 6 4 5 6 4 5 6
4 5 6 4 5 6 4 5 6
A3 =
7 8 9 7 8 9 7 8 9
7 8 9 7 8 9 7 8 9
7 8 9 7 8 9 7 8 9
Or as #Divakar pointed out, it would be advisable to create a single 3D array and store all your data in it (general solution):
n = 3; %// # of times you want to repeat the arrays.
A=[1 4 7;2 5 8;3 6 9];
B = repmat(kron(A',ones(n,1)),1,n);
C = zeros(n,n*size(A,2),3);
C(:,:,1) = B(1:n,:);
C(:,:,2) = B(n+1:2*n,:);
C(:,:,3) = B(2*n+1:end,:);
Try if this fits your needs:
A = [1 4 7;2 5 8;3 6 9];
n = 3; %// size(A,1)
cellArrayOutput = arrayfun(#(x) repmat( A(:,x).',n,n ), 1:size(A,2), 'uni',0)
instead of different variable names, everything is stored in a cell array.
if you insist on different names, I'd recommend to use structs:
A = [1 4 7;2 5 8;3 6 9];
n = 3;
structOutput = struct;
for ii = 1:size(A,2)
structOutput.(['A' num2str(ii)]) = repmat( A(:,ii).', n, n );
end
which gives you:
>> structOutput.A1
ans =
1 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 2 3
and so on.
I don't expect to much performance plus, you should share your full code for further help.

error in SSA matrix creation

i would like to consider following matlab code
http://www.mathworks.com/matlabcentral/fileexchange/8115-singular-spectrum-analysis-smoother/content/ssa.m
especially part
Step1 : Build trayectory matrix
N=length(x1);
if L>N/2;L=N-L;end
K=N-L+1;
X=zeros(L,K);
for i=1:K
X(1:L,i)=x1(i:L+i-1);
end
but when i test on this data
>> x1=[1;3;2;4;5;6;7;8;9];
>> L=5;
>> N=length(x1);
if L>N/2;L=N-L;end
K=N-L+1;
X=zeros(L,K);
for i=1:K
X(1:L,i)=x1(i:L+i-1);
end
>> X
X =
1 3 2 4 5 6
3 2 4 5 6 7
2 4 5 6 7 8
4 5 6 7 8 9
>>
but it does not seems ok,because there is more data length 6 instead of 5 horizontally,so how can i fix it?how should i make sure that other part is also ok?thanks for helping
EDITED:
code should does following example
x1=[2 1 4 3 6 5 8 7];
>> X=create_matrix1(x1,5)
X =
2 1 4 3 6
1 4 3 6 5
4 3 6 5 8
3 6 5 8 7