I want to find easy way to convert a 1x324 cell array which contains matrices to a 2-dimensional matrix.
Each of the cell array's elements is a matrix of size 27x94, so they contain 2538 different values. I want to convert this cell array of matrices to a 324x2538 matrix - where the rows of the output contain each matrix (as a row vector) from the cell array.
To clarify what my data looks like and what I'm trying to create, see this example:
matrix1 = [1,2,3,4,...,94 ; 95,96,97,... ; 2445,2446,2447,...,2538]; % (27x94 matrix)
% ... other matrices are similar
A = {matrix1, matrix2, matrix3, ..., matrix324}; % Matrices are in 1st row of cell array
What I am trying to get:
% 324x2538 output matrix
B = [1 , 2 , ..., 2538 ; % matrix1
2539 , 2540, ..., 5076 ; % matrix2
...
819775, 819776, ..., 822312];
The cell2mat function does exactly that. The doc example:
C = {[1], [2 3 4];
[5; 9], [6 7 8; 10 11 12]};
A = cell2mat(C)
A =
1 2 3 4
5 6 7 8
9 10 11 12
You have your matrix now, so just rework it to contain rows:
B = rand(27,302456); % your B
D = reshape(B,27,94,324); % stack your matrices to 3D
E = reshape(D,1, 2538,324); % reshape each slice to a row vector
E = permute(E,[3 2 1]); % permute the dimensions to the correct order
% Based on sizes instead of fixed numbers
% D = reshape(B, [size(A{1}) numel(A)]);
% E = reshape(D,[1 prod(size(A{1})) numel(A)]);
% E = permute(E,[3 2 1]); % permute the dimensions to the correct order
Or, to one line it from your B:
B = reshape(B,prod(size(A{1})),numel(A)).'
One way to write this would be using cellfun to operate on each element of the cell, then concatenating the result.
% Using your input cell array A, turn all matrices into column vectors
% You need shiftdim so that the result is e.g. [1 2 3 4] not [1 3 2 4] for [1 2; 3 4]
B = cellfun(#(r) reshape(shiftdim(r,1),[],1), A, 'uniformoutput', false);
% Stack all columns vectors together then transpose
B = [B{:}].';
Now I found the solution and I will add it here if anyone have similar problems in future:
for ii = 1:length(A)
B{ii} = A{ii}(:);
end
B = cell2mat(B).';
Related
Given the matrix A = [6 4 1; 1 4 3; 3 4 2;7 6 8] and the array of pairs b = [4 6; 4 1; 1 6], I want to find the pairs given in b in the rows of A without a for loop.
For example, the first pairs is (4,6) or (6,4) , which occurs in the first row of A.
Assuming, you want to find the rows of A which contain the exact pairs given in b, this is how you can do it without a loop:
% Create a matrix of pairs in A
pairs = cat(3, A(:, 1:end-1), A(:, 2:end));
% Reshape b to use bsxfun
b_ = reshape(b', [1 1 size(b')]);
% Get the matches for the pairs and for the flipped pairs
indices = all( bsxfun(#eq, pairs, b_), 3) | all( bsxfun(#eq, pairs, flip(b_,3)), 3);
% Find the indices of the rows with a match
row_indices = find(squeeze(any(any(indices,4),2)));
Please refer to the reference on vectorization for more information on how to make fast computations in Matlab without loops.
I wrote a simple matlab test code where I store 3 matrices (a,b,c) inside of a cell (D). I then create a vector of indexes (idx) so I am able to selected only the first and third matrix out of the cell. The code is presented below:
% Begin code %
a = [0 1; 2 3]; % matrix a
b = [4 5]; % matrix b
c = [5 6; 7 8; 9 10]; % matrix c
D = cell(3,1); % Initialize cell D
D{1,1} = a; D{2,1} = b; D{3,1} = c; % Copy matrices inside cell
idx = [1 3]'; % Indexes vector
D = D(idx); % select matrix a and c from D
% End code (Solution should start from here...) %
if I display D{:,1} what I get is
ans =
0 1
2 3
ans =
5 6
7 8
9 10
My goal is to concatenate the 2 matrices (a,b) out of the cell D in a smart way (using some specific built in matlab function) and possibly avoiding for loop;
This is what I want:
E = [0 1
2 3
5 6
7 8
9 10];
the solution should be the most elegant possible but I am open to any suggestion. The only constrain should be not to change the code I presented, since the solution should be a continuation of what I have written.
NOTICE: Since what I am trying to do should work with an undefined number of matrices (in this example I have only 3 but the could be also 1000), solutions like E = [D{1,:};D{2,1}] are not accepted.
Answer to my question found here:
cat(1,D{:})
how would you use randperm to randomly pick three numbers out of a range of 5 in a vector?
i have a vector like this:
A = [1 2 3 4 5 6 7 8 9 10]
now from every 5 consecutive values i want to randomly pick 3 of them:
A_result = [1 3 5 6 7 9]
any help is appreciated!
This one uses different random indices in every 5-group.
A = [1 2 3 4 5 6 7 8 9 10]
B = reshape(A,5,[]) % (5 x 2)
ind = cell2mat(arrayfun(#(x)sort(randperm(5,3))',1:size(B,2),'UniformOutput',false)) % (3 x 2), row indices into B
ind = bsxfun(#plus,ind,size(B,1)*(0:size(B,2)-1)) % (3 x 2), linear indices into B
C = B(ind) % (3 x 2) result
C(:)' % result vector
Every sort(randperm(5,3))' call generates a random column vector with 3 ascending numbers from 1 to 5, like [1;3;4] or [2;4;5]. arrayfun with the dummy argument x calls this 2 times in this example, because A consists of 2 sub-vectors of length 5. With the argument 'Uniform output' set to false, it generates a cell array of these random vectors, and cell2mat converts it to the (3 x 2)-matrix ind. The bsxfun call converts the values in the matrix ind to a matrix of linear indices into matrix B or A.
For your (900 x 25)-matrix, do
A = rand(900,25); % (900 x 25)
B = A'; % (25 x 900)
ind = cell2mat(arrayfun(#(x)sort(randperm(25,17))',1:size(B,2),'UniformOutput',false)); % (17 x 900), row indices into B
ind = bsxfun(#plus,ind,size(B,1)*(0:size(B,2)-1)); % (17 x 900), linear indices into B
C = B(ind); % (17 x 900), result
You can use reshape and randsample
rA = reshape( A, 5, [] ); % groups of 5 in a a row
A_result = rA( randsample( 5, 3, false ), : );
A_result = reshape( A_result, 1, [] );
You can pre-generate all possible picking patterns, and then randomly select one such pattern for each group. This approach is suitable for small group sizes, otherwise it may use a lot of memory.
A = 1:10; %// example data
n = 5; %// group size. Assumed to divide numel(A)
k = 3; %// how many to pick from each group
S = numel(A);
patterns = nchoosek(1:n, k); %// all possible picking patterns
K = size(patterns, 1);
p = randi(K, S/n, 1); %// generate random indices for patterns
pick = bsxfun(#plus, patterns(p,:).', (0:n:S-1)); %'// to linear indices
A_result = A(pick(:));
I have a simple question but I can't figure it out or find it anywhere.
I have a cell array where c{1} is a vector and c{2} is a vector but of different lengths, up to c{i}. What I want is one vector that is [c{1};c{2};c{3}...c{i}]. What is the most efficient way to do this?
The following one-liner even works for completely inconsistent inputs:
result = [cell2mat(cellfun(#(x) x(:), A, 'uni', 0)')]'
Example:
for:
A{1} = [1, 2, 3, 4, 5];
A{2} = [6; 7; 8; 9];
A{3} = [10, 12; 11, 13];
it returns:
result =
1 2 3 4 5 6 7 8 9 10 11 12 13
Matlab/Octave allows this king of really-not-efficient but very-convenient notation, assuming a is a structure only containing column-vectors:
x = []; #% A fresh new vector/matrix/tensor, who knows?
for i=1:numel(a) #% parse container item by item
x = [x;a{i}]; #% append container item a{i} to x in a column-fashion way
end
This will works but it is bloody inefficient since it will reallocate x each for step and it is not bulletproof (no error handling, no type checking): therefore it will fail if it encounters anything (matrix, string, row vector) but column vector which are likely to be found in such containers.
Anyway, it will ease a not-so-stringent-and-heuristic design, but please consider reimplementing when robust design is needed.
You can padding each cell with zeros, and align the lengths to the longest cell vector. It is done in a loop by iterating each cell vector.
This depends on whether the vectors in c are row or column vectors. But usually the fastest and most compact ways are:
c={[1 2 3], [4 5 6 7 8], [9 10]}
cell2mat(c)
cat(2, c{:})
or
c={[1 2 3]', [4 5 6 7 8]', [9 10]'}
% cell2mat(c) % Doesn't work.
cat(1, c{:})
so personally, I prefer cat.
In Matlab; without loops:
If the cell array contains column vectors and you want to arrange them into one big column vector:
result = vertcat(c{:}); %// vertically concat all vectors
Example:
>> c = {[1;2], [1;2;3]};
>> result = vertcat(c{:})
result =
1
2
1
2
3
If the cell array contains row vectors, you can arrange them as rows of a matrix, filling non-existent values with NaN (or any other value):
M = max(cellfun(#numel, c)); %// max length of vectors
c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0); %// fill with NaN
result = vertcat(c2{:}); %// concat all equal-size row vectors into a matrix
Example:
>> c = {[1 2], [1 2 3]};
>> M = max(cellfun(#numel, c));
>> c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0);
>> result = vertcat(c2{:})
result =
1 2 NaN
1 2 3
a = [1 2; 3 4; 5 6] I want to extract the first and third row of a, so I have x = [1; 3] (indices of rows).
a(x) doesn't work.
Like this: a([1,3],:)
The comma separates the dimensions, : means "entire range", and square brackets make a list.
In MATLAB if one parameter is given when indexing, it is so-called linear indexing. For example if you have 4x3 matrix, the linear indices of the elements look like this, they are growing by the columns:
1 5 9
2 6 10
3 7 11
4 8 12
Because you passed the [1 3] vector as a parameter, the 1st and 3rd elements were selected only.
When selecting whole columns or rows, the following format shall be used:
A(:, [list of columns]) % for whole columns
A([list of rows], :) % for whole rows
General form of 2d matrix indexing:
A([list of rows], [list of columns])
The result is the elements in the intersection of the indexed rows and columns. Results will be the elements marked by X:
A([2 4], [3 4 5 7])
. . C C C . C
R R X X X R X
. . C C C . C
R R X X X R X
Reference and some similar examples: tutorial on MATLAB matrix indexing.
x = a([1 3]) behaves like this:
temp = a(:) % convert matrix 'a' into a column wise vector
x = temp([1 3]) % get the 1st and 3rd elements of 'a'
you could write a loop to iterate across the rows of the matrix:
for i = [1,3]
a(i,:)
end
type this: a([1 3],[1 2])
the output is
ans =
1 2
5 6