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

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

Related

Matlab: Creating a blockwise permutation

I have a vector from 1 to 40 and want to shuffle it in such a way that each block of four integers (ten blocks in total) are shuffled only with themselves.
For example: 3 4 2 1 | 7 6 5 8 | 9 11 10 12 | ...
My original idea was to append ten permutation vectors to eachother and then add a 1 to 40 vector to the big permutation vector, but it didn't work at all as expected and was logically wrong.
Has anyone an idea how to solve this?
data = 10:10:120; % input: values to be permuted
group_size = 4; % input: group size
D = reshape(data, group_size, []); % step 1
[~, ind] = sort(rand(size(D)), 1); % step 2
result = D(bsxfun(#plus, ind, (0:size(D,2)-1)*group_size)); % step 3
result = result(:).'; % step 4
Example result:
result =
20 10 30 40 60 50 70 80 110 100 120 90
How it works
Reshape the data vector into a matrix D, such that each group is a column. This is done with reshape.
Generate a matrix, ind, where each column contains the indices of a permutation of the corresponding column of D. This is done generating independent, uniform random values (rand), sorting each column, and getting the indices of the sorting (second output of sort).
Apply ind as column indices into D. This requires converting to linear indices, which can be done with bsxfun (or with sub2ind, but that's usually slower).
Reshape back into a vector.
You can use A = A(randperm(length(A))) to shuffle an array.
Example in Octave:
for i = 1:4:40
v(i:i+3) = v(i:i+3)(randperm(4));
end

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

adding values to diagonals of matrix using element-wise addition in matlab

I am writing a script that operates on matrices, and I have run into the problem of needing to add the sum of the diagonals of a previous matrix to the diagonal elements of a new matrix. The code I have so far for this particular function (described in more detail below) is:
t = 1;
for k = (m-1):-1:-(m-1)
C = bsxfun(#plus, diag(B, k), d);
g(t) = sum(diag(B, k));
t = t + 1;
end
where d is a 1x3 array, and C is supposed to be a 3x3 array; however, C is being output as a 1x3 array in such a way that the first diagonal is being summed and added to d, then the main diagonal is being summed and added to d, and the final diagonal is being summed and added to d.
Is there a way I can get the values of C to be such that the first diagonal is the sum of it's individual elements added to the last element of d, the main diagonal's individual elements added to the middle element of d, and the bottom diagonal's elements added to the first element of d? (while still working for any array size?)
Here is a picture that describes what I'm trying to achieve:
Thanks!
You can use toeplitz to generate a matrix containing the values that need to be added to your original matrix:
M = [5 5 5; 7 7 7; 9 9 9]; %// data matrix
v = [1 11 4 3 2]; %// data vector
S = toeplitz(v);
S = S(1:(numel(v)+1)/2, (numel(v)+1)/2:end);
result = M+S;
Or, as noted by #thewaywewalk, you can do this more directly as follows:
M = [5 5 5; 7 7 7; 9 9 9]; %// data matrix
v = [1 11 4 3 2]; %// data vector
result = M + toeplitz(v(size(M,1):-1:1), v(size(M,2):end));
Assuming B to be a square shaped matrix, listed in this post would be one bsxfun based vectorized approach. Here's the implementation -
N = size(B,1) %// Store size of B for later usage
%// Find a 2D grid of all indices with kth column representing kth diagonal of B
idx = bsxfun(#plus,[N-numel(B)+1:N+1:N]',[0:2*N-2]*N) %//'
%// Mask of all valid indices as we would see many from the 2D grid
%// going out of bounds of 2D array, B
mask = idx>numel(B) | idx<1
%// Set all out-of-bounds indices to one, so that in next step
%// we could index into B in a vectorized manner and sum those up with d
idx(mask)=1
sum1 = bsxfun(#plus,B(idx),d(:).') %//'
%// Store the summations at proper places in B with masking again
B(idx(~mask)) = sum1(~mask)
Sample run -
B =
1 9 0
7 9 4
6 8 7
d =
4 9 5 8 2
B =
6 17 2
16 14 12
10 17 12
Code:
The following code adds the sums of the diagonals of A to the corresponding diagonals in the matrix B. The code works for matrices A, B of equal size, not necessarily square.
A = magic(4);
B = magic(4);
D = bsxfun(#minus, size(A,2)+(1:size(A,1)).', 1:size(A,2)); %'
sumsDiagsA = accumarray(D(:), A(:)); %// Compute sums of diagonals (your 'd')
B = B + sumsDiagsA(D); %// Add them to the matrix
Explanation:
First we build a matrix that numbers all diagonals beginning from the rightmost diagonal:
>> D = bsxfun(#minus, size(A,2)+(1:size(A,1)).', 1:size(A,2))
D =
4 3 2 1
5 4 3 2
6 5 4 3
7 6 5 4
Then we compute sumsDiagsA as the sum of the diagonals via accumarray:
sumsDiagsA = accumarray(D(:), A(:));
The variable sumsDiagsA is what you refer to as d in your code.
Now we use indexing to the vector containing the sums and add them to the matrix B:
C = B + sumsDiagsA(D);
Assuming you have already computed your vector d, you don't need the accumarray-step and all you need to do is:
D = bsxfun(#minus, size(B,2)+(1:size(B,1)).', 1:size(B,2)); %'
C = B + d(D);

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

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