Hi I want to reshape a matrix but the reshape command doesn't order the elements the way I want it.
I have matrix with elements:
A B
C D
E F
G H
I K
L M
and want to reshape it to:
A B E F I K
C D G H L M
So I know how many rows I want to have (in this case 2) and all "groups" of 2 rows should get appended horizontally. Can this be done without a for loop?
You can do it with two reshape and one permute. Let n denote the number of rows per group:
y = reshape(permute(reshape(x.',size(x,2),n,[]),[2 1 3]),n,[]);
Example with 3 columns, n=2:
>> x = [1 2 3; 4 5 6; 7 8 9; 10 11 12]
x =
1 2 3
4 5 6
7 8 9
10 11 12
>> y = reshape(permute(reshape(x.',size(x,2),n,[]),[2 1 3]),n,[])
y =
1 2 3 7 8 9
4 5 6 10 11 12
Cell array approach -
mat1 = rand(6,2) %// Input matrix
nrows = 3; %// Number of rows in the output
[m,n] = size(mat1);
%// Create a cell array each cell of which is a (nrows x n) block from the input
cell_array1 = mat2cell(mat1,nrows.*ones(1,m/nrows),n);
%// Horizontally concatenate the double arrays obtained from each cell
out = horzcat(cell_array1{:})
Output on code run -
mat1 =
0.5133 0.2916
0.6188 0.6829
0.5651 0.2413
0.2083 0.7860
0.8576 0.3032
0.1489 0.4494
out =
0.5133 0.2916 0.5651 0.2413 0.8576 0.3032
0.6188 0.6829 0.2083 0.7860 0.1489 0.4494
Related
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,:)
I have two vectors, R and C, which have the number of rows and columns, respectively, of submatrices that I need to assemble in a ones matrix I (40x20). There's 12 submatrices total.
R = [4 2 4 4 2 4];
C = [4 16 16 4];
Moreover, all the elements of each submatrix have its value stored in vector k:
k = [3 2 3 3 2 3 2 1 2 2 1 2 2 1 2 2 1 2 3 2 3 3 2 3 ]; % 24 elements
Thus for instance, submatrix M(1:4,1:4) has 4 rows, and 4 columns and value equal to k(1) = 1.
QUESTION: How can I assemble matrix M with all submatrices?
Any ideas?
Thanks!
EDIT:
The matrix M should look like this:
and the submatrices:
and the values of k:
Here is a vectorized solution:
R1 = repelem(1:numel(R), R);
C1 = repelem(1:numel(C), C);
[CC RR] = meshgrid(C1, R1);
idx = sub2ind([numel(R), numel(C)], RR, CC);
result = k(idx);
Instead you can use cell array, fill it with sub matrices and then convert the cell array to a matrix.
carr = cell(numel(R), numel(C));
k1 = reshape(k,numel(R),numel(C));
for ii = 1:numel(R)
for jj = 1:numel(C)
carr(ii,jj)=repmat(K1(ii,jj), R(ii), C(jj));
end
end
result = cell2mat(carr)
I have a M x N x O matrix and I would like to reduce it to a MxN matrix in MATLAB using a vector b of size M that contains the index of the element in the third dimension that is to be kept.
What it does then is build a 2d array with its entries selected from various pages of the original 3d array.
I have this loop but I am interested in a loopless solution.
for i = 1:M
for j = 1:N
tmp(i, j) = P(i, j, b(i));
end
end
The easiest way may just be to remove the j loop in your code:
for ii = 1:M
tmp(ii, :) = P(ii, :, b(ii));
end
But for the sake of comparison, here's a solution without a loop.
Given a 3d array P:
M = 7;
N = 5;
O = 6;
P = ones(M, N, O) .* permute(1:O, [3 1 2]);
(in this case I've used a 3d array where each element is equal to its O index)
and b, of size Mx1 with values from 1..O:
b = randi(O, M, 1)
you can construct the subscripts of all of the elements of P(:,:,1) and use b to select which plane to use:
[rr, cc] = ndgrid(1:M, 1:N);
inds = sub2ind(size(P), rr(:), cc(:), b(rr(:)));
tmp = reshape(P(inds), M, N)
For:
b.' = 5 4 1 5 3 1 3
we get:
tmp =
5 5 5 5 5
4 4 4 4 4
1 1 1 1 1
5 5 5 5 5
3 3 3 3 3
1 1 1 1 1
3 3 3 3 3
The elements of each row corresponds to the element in b as expected.
A simple example to illustrate all elements of a matrix multiplying each element of a vector to generate a 3D array.
M = reshape(1:12,4,3);
V = 1:2;
n = length(V);
A = nan([size(M),n]);
for ii = 1 : n
A(:,:,ii) = M * V(ii);
end
then
A(:,:,1) =
1 5 9
2 6 10
3 7 11
4 8 12
A(:,:,2) =
2 10 18
4 12 20
6 14 22
8 16 24
Or by repmat both M and V to the size of [4,3,2],
A = repmat(M,1,1,n) * reshape(V(ones(size(M)),:),[size(M),n])
It creates two 3D array by repmat besides the resulting 3d array A.
How to make it efficiently WITHOUT for loop and save the memory use?
According to the answer by #Lincoln,
A = bsxfun(#times, repmat(M,1,1,n), reshape(1:n, 1, 1, n));
repmat the vector V to 3d is not necessary.
Is it possible to create NO 3d array if the final result wanted is 2d, the sum of A along the 3rd dim? By for loop, the code would be
M = reshape(1:12,4,3);
V = 1:2;
n = length(V);
A = 0;
for ii = 1 : n
A = A + M * V(ii);
end
Try replacing the for.. loop with:
M_rep = repmat(M,1,1,n) %//repeat M in the 3rd dimension n times
v = reshape(1:n, 1, 1, n) %//create a vector [1 2 .. n] pointing in the third dimension
A = bsxfun(#times, M_rep, v) %//vector multiply them in the third dimension
In your above example, n=2.
EDIT (to your added question): To sum without allocating A:
B = sum(bsxfun(#times, M_rep, v),3);
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);