Reorder a matrix according to the mean of its rows - arrays

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.

Related

Removing all rows from matrix A in matrix B

I have in MATLAB a matrix A with RGB-values, lets say
A = [1 2 3;
4 5 6;
7 8 9]
and a matrix B lets say
B = [1 2 3;
2 2 2]
Now I want to remove all rows of B from A.
The result would be:
A* = [4 5 6;
7 8 9]
How can this be done efficiently in MATLAB?
To find which rows of A are present in B:
rowmatches = ismember(A,B,'rows')
The above gives a binary vector the length of the number of rows in A. You can then ask for the subset of A rows that were not in B:
output = A(~rowmatches,:)

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

Array filter based on multiple columns

Suppose I have a 4 x n array:
A = [1 2 3 4; ...
2 4 8 9; ...
6 7 9 4; ...
1 8 3 4];
I want to filter the whole array based on the content of the first two columns.
For example, if I want to return array rows which contain a 2 in the first two columns, the answer I'm looking for isL
R = [1 2 3 4;...
2 4 8 9];
Or, if I want to return rows containing a 1 in the first two columns, the answer I'm looking for is...
A = [1 2 3 4;...
1 8 3 4];
I'm sure it's obvious but how can I do this in MATLAB? Filtering the whole array based on find or evaluation commands (e.g. A == 2) is totally fine. It's the filtering based on multiple columns in any order I can't figure out.
To check for a given number, just apply any along 2nd dimension restricted to the desired columns, and use that as a logical index to select the desired rows:
cols = [1 2]; %// columns to look at
val = 1; %// value to look for
R = A(any(A(:, cols)==val, 2), :);
If you want to look for several values, for example, select all rows that contain either 2 or 3 in columns 1 or 2: use ismember instead of ==:
cols = [1 2]; %// columns to look at
vals = [2 3]; %// values to look for
R = A(any(ismember(A(:, cols), vals), 2), :);
If you want to check if the numbers are within a range:
cols = [1 2]; %// columns to look at
v1 = 6; %// numbers should be greater or equal to this...
v2 = 8; %// ...and less than this
R = A(any(A(:, cols)>=v1, 2) & any(A(:, cols)<v2, 2), :);

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)'

Store matrix from a loop in Matlab

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).

Resources