How to group rows with same column values? - matlab

Given the matrix with coordinates in 3D space and values for two variables (say a and b) in two matrices I would like to merge rows for same points into a common matrix.
To clearly explain the matter, let's say we have matrices
A=[posX, posY, posZ, a]
and
B=[posX, posY, posZ, b]
and would like to combine them into
AB = [posX, posY, posZ, a, b]
for example
A = [0 0 1 1; 0 1 0 4; 5 0 12 8];
B = [0 0 0 5; 0 1 0 3; 5 11 7 7];
would give
AB = [0 0 0 0 5; 0 0 1 1 0; 0 1 0 4 3; 5 0 12 8 0; 5 11 7 0 7];
In order to do that I first created
ATemp = [A, zeros(length(A,0)]
and
BTemp = [B(:, [1 2 3]), zeros(length(B),1), B(:,4)]
and then tried to use functions accumarray and grpstats but haven't managed to form the AB matrix.
I would be very thankful if anyone suggested the way to get the desired matrix.

AB=union(A(:,1:3),B(:,1:3),'rows');
AB(ismember(AB,A(:,1:3),'rows'),4)=A(:,4);
AB(ismember(AB(:,1:3),B(:,1:3),'rows'),5)=B(:,4)
[edit] This solution is only valid if each (x,y,z)-point occurs only once in each matrix. If there are several, there is a dimension mismatch in the second line (and/or the third).

Related

Zero pad a vector in MATLAB

I have a vector that contains 5 numbers and I want to pad it with zeros. How can I do it?
A = [1 2 3 4 5].';
I want the zero padded vector to be like this:
A_new = [0 0 0 0 0 1 2 3 4 5].';
Also, for another case, I want to assign 1, 3, 4 to matrix W as follows, with all else being zeros. The length of W is 7. W = [0 1 0 0 3 0 4].
You can use following code
newA = [zeros(5,1); A]
About another case. You need something like
inds = [2 5 7];
elems = [1 3 4];
W = zeros(7,1);
W(inds) = elems

take from matrix non-zero rows per column

I have a matrix A. Suppose it is:
A=[1 0 8;
0 0 2;
3 0 5;
4 8 0;
0 5 3;
6 1 3;
1 6 5;
0 7 1]
and I want to get the non-zero rows subscripts per column in a new matrix.
In my example that will be,
B = [ 1 3 4 6 7 0 0 0;
4 5 6 7 8 0 0 0;
1 2 3 5 6 7 8 0]
In terms of just size, if A=(m,n), B will be B=(n,m) (the transpose). In terms of content, B contains the subscripts of the non-zero rows in A as described above.
Here is one way:
mask = ~sort(~A); %// destination of row indexes in output
[ii,~]=find(A); %// get the row indexes
B = zeros(size(A));
B(mask) = ii; B=B.' %'//write indexes to output and transpose
I think this does what you want (get the non-zero row indices per column). It's very similar to this other question:
[r c] = size(A);
M = bsxfun(#times, A~=0, 1:size(A,2)).'; %'// substitute values by indices
[~, rows] = sort(M~=0,'descend'); %//'' push zeros to the end
cols = repmat(1:r,c,1);
ind = sub2ind([c r],rows(:),cols(:));
B = repmat(NaN,c,r);
B(:) = M(ind).';
B = B.';
Result:
>> B
B =
1 3 4 6 7 0 0 0
4 5 6 7 8 0 0 0
1 2 3 5 6 7 8 0

Multiplying a small matrix by a big matrix

I'm trying to multiply every element in a small matrix (let's say 2x2) with every position in a big matrix (let's say 4x4), element by element.
So I want:
1 2 3 4 1 0 3 0
1 0 1 2 3 4 0 0 0 0
0 0 'x' 1 2 3 4 = 1 0 3 0
1 2 3 4 0 0 0 0
The small matrix is applied as many times as it fits, and the multiplication is element by element. I've tried a bunch of loops, but that doesn't feel right in MATLAB, there must be prettier ways of doing it?
One possibility is to use repmat to repeat the small matrix as many times as necessary:
C = repmat(A,size(B,1)/size(A,1),size(B,2)/size(A,2)).*B
Another possibility, which avoids repmat: cut up the large matrix, arrange the pieces in the third and fourth dimensions, and use bsxfun to do the multiplication:
[m n] = size(A);
[M N] = size(B);
T = permute(reshape(B,M,n,[]), [2 1 3]);
T = permute(reshape(T,n,m,[],size(T,3)),[2 1 3 4]);
C = cell2mat(squeeze(mat2cell(bsxfun(#times,T,A),m,n,ones(1,M/m),ones(1,N/n))));
(The two lines T = ... do the cutting, and are due to A. Donda.)
The advantage of this approach is that, if memory is an issue, you can overwrite B instead of defining T, thus saving memory:
[m n] = size(A);
[M N] = size(B);
B = permute(reshape(B,M,n,[]),[2 1 3]);
B = permute(reshape(B,n,m,[],size(B,3)),[2 1 3 4]);
C = cell2mat(squeeze(mat2cell(bsxfun(#times,B,A),m,n,ones(1,M/m),ones(1,N/n))));
If you have the image processing toolbox, you can try blkproc:
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> B = [1 0; 0 0];
>> C = blkproc(A,size(B),#(x) x.*B)
C =
16 0 3 0
0 0 0 0
9 0 6 0
0 0 0 0

Matlab Extend Diagonal by one

Suppose I have a matrix A, and I'd like to get the matrix [A 0; 0 1]. Is there a built function to do this?
So if my matrix is [2 3; 1 4], I'd get back [2 3 0; 1 4 0; 0 0 1]
The easiest way is:
newA = A;
newA(end+1,end+1) = 1;
This works because you can index outside an array for assignments, because end indicates the last element (here in row and column), and because Matlab pads with zeros when you grow an array. If you just want to grow A, you can even skip the creation of newA, of course.
I always use matrix concatenation for problems like this
So for your example:
A = [2 3; 1 4]
A = [A A(:,1)*0; A(1,:)*0 1]
produces
A =
2 3 0
1 4 0
0 0 1
The nice thing about this trick is that its very flexible and you can do all sorts of tranformations
very easily. For example
A = [2 3; 1 4]
A = [1 A(1,:)*0; A(:,1)*0 A]
produces
A =
1 0 0
0 2 3
0 1 4

Set column to 0 with probability p

I've got a matrix A with the dimensions m X n. For every column i (i > 0and i <= n) I want to flip a coin and fill the whole column with 0 values with probability p. How can this be accomplished in MATLAB?
Example:
A = [1 2 3 4; 5 6 7 8] and p = 0.5 could result in
A' = [1 0 3 0; 5 0 7 0]
You can use the function rand() to generate an array of uniformly distributed random numbers, and use logical indexing to select colums where that array is less than p:
A = [1 2 3 4; 5 6 7 8];
p = 0.5;
A(:, rand(size(A,2), 1)<p) = 0
A =
0 2 0 0
0 6 0 0
You can do something like bsxfun(#times, A, rand(1, size(A, 2)) > p). Alex's answer is admittedly better, though.