Store matrix from a loop in Matlab - arrays

I have a 5 by 3 matrix, e.g the following:
A=[1 1 1; 2 2 2; 3 3 3; 4 4 4; 5 5 5]
I run a for loop:
for i = 1:5
AA = A(i)'*A(i);
end
My question is how to store each of the 5 (3 by 3) AA matrices?
Thanks.

You could pre-allocate enough memory to the AA matrix to hold all the results:
[r,c] = size(A); % get the rows and columns of A (r and c respectively)
AA = zeros(c,c,r); % pre-allocate memory to AA for all 5 products
% (so we have 5 3x3 arrays)
Now do almost the same loop as above BUT realize that A(i) in the above code only returns one element whereas you want the full row. So you want the data from row i but all columns which can be represented as 1:3 or just the colon :
for i=1:r
AA(:,:,i) = A(i,:)' * A(i,:);
end
In the above, A(i,:) is the ith row of A and we are setting all rows and columns in the third dimension (i) of AA to the result of the product.

Assuming, as in Geoff's answer, that you mean A(i,:)'*A(i,:) (to get 5 matrices of size 3x3 in your example), you can do it in one line with bsxfun and permute:
AA = bsxfun(#times, permute(A, [3 2 1]), permute(A, [2 3 1]));
(I'm also assuming that your matrices only contain real numbers, as in your example. If by ' you really mean conjugate transpose, you need to add a conj in the above).

Related

Collapsing matrix into columns

I have a 2D matrix where the № of columns is always a multiple of 3 (e.g. 250×27) - due to a repeating organisation of the results (A,B,C, A,B,C, A,B,C, and so forth). I wish to reshape this matrix to create a new matrix with 3 columns - each containing the aggregated data for each type (A,B,C) (e.g. 2250×3).
So in a matrix of 250×27, all the data in columns 1,4,7,10,13,16,19,22,25 would be merged to form the first column of the resulting reshaped matrix.
The second column in the resulting reshaped matrix would contain all the data from columns 2,5,8,11,14,17,20,23,26 - and so forth.
Is there a simple way to do this in MATLAB? I only know how to use reshape if the columns I wanted to merge were adjacent (1,2,3,4,5,6) rather than non-adjacent (1,4,7,10,13,16) etc.
Shameless steal from #Divakar:
B = reshape( permute( reshape(A,size(A,1),3,[]), [1,3,2]), [], 3 );
Let A be your matrix. You can save every third column in one matrix like:
(Note that you don't have to save them as matrices separately but it makes this example easier to read).
A = rand(27); %as test
B = A(:,1:3:end);
C = A(:,2:3:end);
D = A(:,3:3:end);
Then you use reshape:
B = reshape(B,[],1);
C = reshape(C,[],1);
D = reshape(D,[],1);
And finally put it all together:
A = [B C D];
You can just treat every set of columns as a single item and do three reshapes together. This should do the trick:
[save as "reshape3.m" file in your Matlab folder to call it as a function]
function out = reshape3(in)
[~,C]=size(in); % determine number of columns
if mod(C,3) ~=0
error('ERROR: Number of rows must be a multiple of 3')
end
R_out=numel(in)/3; % number of rows in output
% Reshape columns 1,4,7 together as new column 1, column 2,5,8 as new col 2 and so on
out=[reshape(in(:,1:3:end),R_out,1), ...
reshape(in(:,2:3:end),R_out,1), ...
reshape(in(:,3:3:end),R_out,1)];
end
Lets suppose you have a 3x6 matrix A
A = [1 2 3 4 5 6;6 5 4 3 2 1;2 3 4 5 6 7]
A =
1 2 3 4 5 6
6 5 4 3 2 1
2 3 4 5 6 7
you extract the size of the matrix
b =size(A)
and then extract each third column for a single row
c1 = A((1:b(1)),[1:3:b(2)])
c2 = A((1:b(1)),[2:3:b(2)])
c3 = A((1:b(1)),[3:3:b(2)])
and put them in one matrix
A_result = [c1(:) c2(:) c3(:)]
A_result =
1 2 3
6 5 4
2 3 4
4 5 6
3 2 1
5 6 7
My 2 cents:
nRows = size(matrix, 1);
nBlocks = size(matrix, 2) / 3;
matrix = reshape(matrix, [nRows 3 nBlocks]);
matrix = permute(matrix, [1 3 2]);
matrix = reshape(matrix, [nRows * nBlocks 1 3]);
matrix = reshape(matrix(:), [nRows * nBlocks 3]);
Here's my 2 minute take on it:
rv = #(x) x(:);
ind = 1:3:size(A,2);
B = [rv(A(:,ind)) rv(A(:,ind+1)) rv(A(:,ind+2))];
saves a few ugly reshapes, may be a bit slower though.
If you have the Image Processing Toolbox, im2col is a very handy solution:
out = im2col(A,[1 4], 'distinct').'
Try Matlab function mat2cell, I think this form is allowed.
X is the "start matrix"
C = mat2cell(X, [n], [3, 3, 3]); %n is the number of rows, repeat "3" as many times as you nedd
%extract every matrix
C1 = C{1,1}; %first group of 3 columns
C2 = C{1,2}; %second group of 3 columns
%repeat for all your groups
%join the matrix with vertcat
Cnew = vertcat(C1,C2,C3); %join as many matrix n-by-3 as you have

How to do a matrix manipulation on Matlab?

I have a matrix A of size m x n and another matrix b of size 1 x n (in Matlab).
The matrix b is such that it consists of sequences of 1s, then sequences of 2s, then sequences of 3s, etc. up to some value k.
(For example b = [1 1 1 2 2 2 3 4 4], n = 9)
I want to take A, and for each row in A, choose the max in each segment, zeroing everything else in that subsequence.
So, for example, for a row A = [0 -1 2 3 4 1 3 4 5]) I would get
[0 0 2 0 4 0 3 0 5]
If there are multiple rows in A (m > 1), this should happen for each row.
I can do it easily using for loops, but it works very slowly, because I loop both over m and n.
Is there a "oneliner" to do it in Matlab, or something simple that works fast?
If A is a single row, accumarray can do the job using an ad hoc function:
result = accumarray(b(:), A(:) ,[] , #(x) {x==max(x)});
result = vertcat(result{:}).' .* A;
Not sure how fast this will be, since it uses cells.
If A has several rows, you can use a loop over the rows.

summing over a matrix in different parts of that matrix in matlab

In a matrix, how can we sum part by part of the elements? Consider the primary matrix in a way that can be divided into smaller m by n matrix. then i want to sum the whole elements of each m by n matrix together and put the number instead of the m by n matrix
for example consider the following matrix, i want to sum every four elements and create another matrix:
A = [1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16];
And after summing i want to have:
B = [14 22
46 54];
I this example i summed 4 elements as a matrix of 2 by 2 then for example the result of summing 1,2,5 and 6 seats in the first element of the new matrix.
Let
m = 2; %// number of rows per block
n = 2; %// number of columns per block
You can do the sum with blockproc (from the Image Processing Toolbox), which is very suited for this task:
B = blockproc(A, [m n], #(x) sum(x.data(:)));
Or, if you build the appropriate indices, you can use accumarray:
[ii jj] = ndgrid(1:size(A,1), 1:size(A,2));
B = accumarray([ceil(ii(:)/n) ceil(jj(:)/m)], A(:))
One approach -
B = squeeze(sum(reshape(sum(reshape(A,m,[])),size(A,1)/m,n,[]),2))
Another approach if you would like to avoid squeeze, which is sometimes slower -
B = reshape(sum(reshape(reshape(sum(reshape(A,m,[])),size(A,1)/m,[])',n,[])),[],size(A,1)/m)'

Non-repeated arrays in a matrix in matlab

I am looking for non-repeated rows in a matrix.
Assume:
A =
8 1
2 2
2 2
2 2
2 2
3 6
5 7
5 7
I would like to get "B" which is:
B=
8 1
3 6
Please mind C=unique(A,'rows') will give us unique rows of "A" which include repeated and non-repeated arrays and only remove repetitious rows. It means:
C =
2 2
3 6
5 7
8 1
"C" is not the one that I am looking for.
Any help would be greatly appreciated!
Use the second and third outputs of unique as follows:
[~, ii, jj] = unique(A,'rows');
kk = find(histc(jj,unique(jj))==1);
B = A(sort(ii(kk)),:);
Or use this more direct bsxfun-based approach:
B = A(sum(squeeze(all(bsxfun(#eq, A.', permute(A, [2 3 1])))))==1,:);
These two approaches work in quite generally: A may have any number of columns, and may contain non-integer values.
If A always has two columns and contains only integer values, you can also do it with accumarray, using the sparse option (sixth input argument) to save memory in case of large values:
[ii jj] = find(accumarray(A, 1, [], #sum, 0, true)==1);
B = [ii jj];
Or you can use sparse instead of accumarray:
[ii jj] = find(sparse(A(:,1),A(:,2),1)==1);
B = [ii jj];
If you don't care about the order of the rows, try this -
[C,~,ic] = unique(A,'rows','legacy')
B = C(histc(ic,unique(ic))==1,:)

Reorder a matrix according to the mean of its rows

Given a matrix A m x n I would like to reorganize its rows so that going from row 1 to row n there is a growing mean value over the row.
Is there a simple way of doing so?
E.g. Input A = [5 5 5; 3 3 3; 2 2 2; 4 4 4] Output B = [2 2 2; 3 3 3; 4 4 4; 5 5 5]
I think you mean rows, not columns; and mean, not median:
[~, ind] = sort(mean(A.')); %'// get indices of sorting the row means
B = A(ind,:); %// apply that sorting to the matrix
(you may save some time using sum instead of mean).
If you really mean columns:
[~, ind] = sort(mean(A));
B = A(:,ind);
If you really mean median, replace mean by median.

Resources