How to stack submatrices of a matrix to reduce dimensionality - matlab

I couldn't find a good solution for this:
I have a matrix of this size: 60x10x3
And I want to transform it into a matrix of this size: 600x3
Basically I want to stack the 10 matrices with the dimension 60x3 next to each other in the first dimension.
How can I achieve that elegantly in matlab?

It seems that I don't understand what the intended output is, but here are two different ways to achieve it. I added the loop to create different numbers so the results can be studied.
Method 1 - Stack Vertically or Horizontally
s = zeros(60,10,3);
for x = 1:9
s(:,x,:) = x;
end
t = reshape(s, 600, 3); %vert
u = t'; %hori
Method 2 - Stack 3rd dimension Vertically or horizontally
s = zeros(60,10,3);
for x = 1:9
s(:,x,:) = x;
end
t = [s(:,:,1) , s(:,:,2), s(:,:,3)]; % hori
t = [s(:,:,1) ; s(:,:,2); s(:,:,3)]; % vert
Hope it helps, but this shows that there are multiple ways to achieve the same output in Matlab. Very powerful tool indeed.

A = rand(60, 10, 3);
B = reshape(A, [], size(A, 3));
should work for any dimensions of A.

Here is a solution that
stack[s] the 10 matrices with the dimension 60x3 next to each other in the first dimension.
a = rand(60,3,10);
% swap the 2nd and 3rd dimention
b = permute(a,[1,3,2]);
% condense to 2d
c = b(:,:);
% reshape x, y and z seperately so each group of 60 xs/ys/zs appends to the end of the previous group
x=reshape(c(:,1:3:end),[],1);
y=reshape(c(:,2:3:end),[],1);
z=reshape(c(:,3:3:end),[],1);
% condense to one 600*3 matrix
d = [x y z];

Related

Extract and then sum sub-matrices in Matlab [duplicate]

Given a square matrix of say size 400x400, how would I go about splitting this into constituent sub-matrices of 20x20 using a for-loop? I can't even think where to begin!
I imagine I want something like :
[x,y] = size(matrix)
for i = 1:20:x
for j = 1:20:y
but I'm unsure how I would proceed. Thoughts?
Well, I know that the poster explicitly asked for a for loop, and Jeff Mather's answer provided exactly that.
But still I got curious whether it is possible to decompose a matrix into tiles (sub-matrices) of a given size without a loop. In case someone else is curious, too, here's what I have come up with:
T = permute(reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n, m, []), [2 1 3])
transforms a two-dimensional array A into a three-dimensional array T, where each 2d slice T(:, :, i) is one of the tiles of size m x n. The third index enumerates the tiles in standard Matlab linearized order, tile rows first.
The variant
T = permute(reshape(A, size(A, 1), n, []), [2 1 3]);
T = permute(reshape(T, n, m, [], size(T, 3)), [2 1 3 4]);
makes T a four-dimensional array where T(:, :, i, j) gives the 2d slice with tile indices i, j.
Coming up with these expressions feels a bit like solving a sliding puzzle. ;-)
I'm sorry that my answer does not use a for loop either, but this would also do the trick:
cellOf20x20matrices = mat2cell(matrix, ones(1,20)*20, ones(1,20)*20)
You can then access the individual cells like:
cellOf20x20matrices{i,j}(a,b)
where i,j is the submatrix to fetch (and a,b is the indexing into that matrix if needed)
Regards
You seem really close. Just using the problem as you described it (400-by-400, divided into 20-by-20 chunks), wouldn't this do what you want?
[x,y] = size(M);
for i = 1:20:x
for j = 1:20:y
tmp = M(i:(i+19), j:(j+19));
% Do something interesting with "tmp" here.
end
end
Even though the question is basically for 2D matrices, inspired by A. Donda's answer I would like to expand his answer to 3D matrices so that this technique could be used in cropping True Color images (3D)
A = imread('peppers.png'); %// size(384x512x3)
nCol = 4; %// number of Col blocks
nRow = 2; %// number of Row blocks
m = size(A,1)/nRow; %// Sub-matrix row size (Should be an integer)
n = size(A,2)/nCol; %// Sub-matrix column size (Should be an integer)
imshow(A); %// show original image
out1 = reshape(permute(A,[2 1 4 3]),size(A,2),m,[],size(A,3));
out2 = permute(reshape(permute(out1,[2 1 3 4]),m,n,[],size(A,3)),[1 2 4 3]);
figure;
for i = 1:nCol*nRow
subplot(nRow,nCol,i); imshow(out2(:,:,:,i));
end
The basic idea is to make the 3rd Dimension unaffected while reshaping so that the image isn't distorted. To achieve this, additional permuting was done to swap 3rd and 4th dimensions. Once the process is done, the dimensions are restored as it was, by permuting back.
Results:
Original Image
Subplots (Partitions / Sub Matrices)
Advantage of this method is, it works good on 2D images as well.
Here is an example of a Gray Scale image (2D). Example used here is MatLab in-built image 'cameraman.tif'
With some many upvotes for the answer that makes use nested calls to permute, I thought of timing it and comparing to the other answer that makes use of mat2cell.
It is true that they don't return the exact same thing but:
the cell can be easily converted into a matrix like the other (I timed this, see further down);
when this problem arises, it is preferable (in my experience) to have the data in a cell since later on one will often want to put the original back together;
Anyway, I have compared them both with the following script. The code was run in Octave (version 3.9.1) with JIT disabled.
function T = split_by_reshape_permute (A, m, n)
T = permute (reshape (permute (reshape (A, size (A, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
endfunction
function T = split_by_mat2cell (A, m, n)
l = size (A) ./ [m n];
T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1));
endfunction
function t = time_it (f, varargin)
t = cputime ();
for i = 1:100
f(varargin{:});
endfor
t = cputime () - t;
endfunction
Asizes = [30 50 80 100 300 500 800 1000 3000 5000 8000 10000];
Tsides = [2 5 10];
As = arrayfun (#rand, Asizes, "UniformOutput", false);
for d = Tsides
figure ();
t1 = t2 = [];
for A = As
A = A{1};
s = rows (A) /d;
t1(end+1) = time_it (#split_by_reshape_permute, A, s, s);
t2(end+1) = time_it (#split_by_mat2cell, A, s, s);
endfor
semilogy (Asizes, [t1(:) t2(:)]);
title (sprintf ("Splitting in %i", d));
legend ("reshape-permute", "mat2cell");
xlabel ("Length of matrix side (all squares)");
ylabel ("log (CPU time)");
endfor
Note that the Y axis is in log scale
Performance
Performance wise, using the nested permute will only be faster for smaller matrices where big changes in relative performance are actually very small changes in time. Note that the Y axis is in log scale, so the difference between the two functions for a 100x100 matrix is 0.02 seconds while for a 10000x10000 matrix is 100 seconds.
I have also tested the following which will convert the cell into a matrix so that the return values of the two functions are the same:
function T = split_by_mat2cell (A, m, n)
l = size (A) ./ [m n];
T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1), 1);
T = reshape (cell2mat (T(:)'), [m n numel(T)]);
endfunction
This does slow it down a bit but not enough to consider (the lines will cross at 600x600 instead of 400x400).
Readability
It is so much more difficult to get your head around the use of the nested permute and reshape. It's mad to use it. It will increase maintenance time by a lot (but hey, this is Matlab language, it's not supposed to be elegant and reusable).
Future
The nested calls to permute does not expand nicely at all into N dimensions. I guess it would require a for loop by dimension (which would not help at all the already quite cryptic code). On the other hand, making use of mat2cell:
function T = split_by_mat2cell (A, lengths)
dl = arrayfun (#(l, s) repmat (l, s, 1), lengths, size (A) ./ lengths, "UniformOutput", false);
T = mat2cell (A, dl{:});
endfunction
Edit (and tested in Matlab too)
The amount of upvotes on the answer suggesting to use permute and reshape got me so curious that I decided to get this tested in Matlab (R2010b). The results there were pretty much the same, i.e., it's performance is really poor. So unless this operation will be done a lot of times, in matrices that will always be small (less than 300x300), and there will always be a Matlab guru around to explain what it does, don't use it.
If you want to use a for loop you can do this:
[x,y] = size(matrix)
k=1; % counter
for i = 1:20:x
for j = 1:20:y
subMatrix=Matrix(i:i+19, j:j+19);
subMatrixCell{k}=subMatrix; % if you want to save all the
% submatrices into a cell array
k=k+1;
end
end

Sum over blocks in a 3D matrix - MATLAB

For a 3N by 3N by 3N matrix A, I would like to derive a N by N by N matrix B whose entries come from summation over blocks in A.
For example, B(1,1,1) = sum of all elements of A(1:3,1:3,1:3).
Basically, A is kind of a high resolution matrix and B is a low resolution matrix from summing over entries in A.
If memory is not a concern, you can use a "labelling" approach: build a 3-component label to group the elements of A, and use that label as the first input argument to accumarray to do the sum. The label uses integers from 1 to N, so the result of accumarray already has the desired shape (NxNxN).
N = 5;
F = 3; %// block size per dimension
A = rand(15,15,15); %// example data. Size FN x FN x FN
[ii jj kk] = ind2sub(size(A), 1:numel(A));
label = ceil([ii.' jj.' kk.']/F);
result = accumarray(label, A(:));
reshape + sum based approach and as such has to be pretty efficient -
sumrows = sum(reshape(A,3,[]),1); %// Sum along rows
sumcols = sum(reshape(sumrows,N,3,[]),2); %// Sum along cols
B = reshape(sum(reshape(sumcols,N*N,3,[]),2),N,N,N); %// Sum along 3rd dim
If you are crazy about one-liners, here's that combining all steps into one -
B = reshape(sum(reshape(sum(reshape(sum(reshape(A,3,[]),1),N,3,[]),2),N*N,3,[]),2),N,N,N);
For a 2D matrix, this would work:
B = reshape(sum(im2col(A, [3 3], 'distinct')), [N N]);
NB: You need the image processing toolbox.
But for 3D matrices, I don't know of any built-in function equivalent to im2col. You might have to use a loop. Left as an exercise to the reader ;)

How can I concatenate many column vectors into one matrix?

I want to concatenate 100 column vectors into one matrix. The code is the following:
for i = 1:100
X = mean(TMP(i).SonarReturnData.BeamsOutput(1:200, 25:35), 2);
end
What I want is to concatenate all 100 column vectors (each 200x1 length vectors) into one matrix (which should become a 200x100 matrix). I tried to use C = cat(2,X(:)), but it didn't work. Does anyone have an idea? Thank you.
Just pre-allocate X with your desired 200x100 size and then index into columns of X appropriately in your loop. I.e.,
X = zeros(200, 100);
for i = 1:100
X(:,i) = mean(TMP(i).SonarReturnData.BeamsOutput(1:200, 25:35), 2);
end

Calculate distance, given a set of coordinates

my question is quite trivial, but I'm looking for the vectorized form of it.
My code is:
HubHt = 110; % Hub Height
GridWidth = 150; % Grid length along Y axis
GridHeight = 150; % Grid length along Z axis
RotorDiameter = min(GridWidth,GridHeight); % Turbine Diameter
Ny = 31;
Nz = 45;
%% GRID DEFINITION
dy = GridWidth/(Ny-1);
dz = GridHeight/(Nz-1);
if isequal(mod(Ny,2),0)
iky = [(-Ny/2:-1) (1:Ny/2)];
else
iky = -floor(Ny/2):ceil(Ny/2-1);
end
if isequal(mod(Nz,2),0)
ikz = [(-Nz/2:-1) (1:Nz/2)];
else
ikz = -floor(Nz/2):ceil(Nz/2-1);
end
[Y Z] = ndgrid(iky*dy,ikz*dz + HubHt);
EDIT
Currently I am using this solution, which has reasonable performances:
coord(:,1) = reshape(Y,[numel(Y),1]);
coord(:,2) = reshape(Z,[numel(Z),1]);
dist_y = bsxfun(#minus,coord(:,1),coord(:,1)');
dist_z = bsxfun(#minus,coord(:,2),coord(:,2)');
dist = sqrt(dist_y.^2 + dist_z.^2);
I disagree with Dan and Tal.
I believe you should use pdist rather than pdist2.
D = pdist( [Y(:) Z(:)] ); % a compact form
D = squareform( D ); % square m*n x m*n distances.
I agree with Tal Darom, pdist2 is exactly the function you need. It finds the distance for each pair of coordinates specified in two vectors and NOT the distance between two matrices.
So I'm pretty sure in your case you want this:
pdist2([Y(:), Z(:)], [Y(:), Z(:)])
The matrix [Y(:), Z(:)] is a list of every possible coordinate combination over the 2D space defined by Y-Z. If you want a matrix containing the distance from each point to each other point then you must call pdist2 on this matrix with itself. The result is a 2D matrix with dimensions numel(Y) x numel(Y) and although you haven't defined it I'm pretty sure that both Y and Z are n*m matrices meaning numel(Y) == n*m
EDIT:
A more correct solution suggested by #Shai is just to use pdist since we are comparing points within the same matrix:
pdist([Y(:), Z(:)])
You can use the matlab function pdist2 (I think it is in the statistics toolbox) or you can search online for open source good implementations of this function.
Also,
look at this unswer: pdist2 equivalent in MATLAB version 7

How do I label two vectors in Matlab?

I have a 2 column matrix(called M, which I visualize as two vectors using Matlab's plot command(plot(M)). I have two issues:
I want to label the vectors themselves on the plot.
I want to label each row of the matrix(i.e. each vector component) on the plot.
How would I go about doing those things?
An example:
M = cumsum(rand(10,2) - 0.5);
x = 1:size(M,1);
plot(x, M(:,1), 'b.-', x, M(:,2), 'g.-')
legend('M1', 'M2')
for i=x
text(i+0.1, M(i,1), sprintf('%.2f', M(i,1)), 'FontSize',7, 'Color','b');
text(i+0.1, M(i,2), sprintf('%.2f', M(i,2)), 'FontSize',7, 'Color','g');
end
Alternatively, you can use:
datacursormode()
which will enable the user to just point and click on points to see the data labels.
You may need to tweak this to get the positions of the labels exactly how you want them, but something like this will do the trick.
M = [1 2; 3 4; 5 6]
plot(M)
nrows = size(M, 1);
ncols = size(M, 2);
x = repmat(nrows - .3, 1, ncols);
y = M(end, :) - .3;
labels = cellstr([repmat('Col', ncols, 1), num2str((1:ncols)')]);
text(x, y, labels)
You can label each axis with the function:
xlabel('label')
ylabel('label')
These can also take cell arguments, where each row is a new line. That's handy for showing units. Labeling each point on the figure can be done as so:
for i=1:length(M)
text(M(i,1),M(i,2),'Label Text')
end
The label text can also be a string variable that you can edit with sprintf and make special strings for each point.