finding indices of multiple corresponding rows of a matrix in matlab [duplicate] - matlab

This question already has answers here:
How can I find indices of each row of a matrix which has a duplicate in matlab?
(3 answers)
Closed 8 years ago.
I have two matrices and I want to find the indices of rows in Matrix B which have the same row values in Matrix A. Let me give a simple example:
A=[1,2,3; 2,3,4; 3,5,7; 1,2,3; 1,2,3; 5,8,6];
B=[1,2,3; 29,3,4; 3,59,7; 1,29,3; 1,2,3; 5,8,6;1,2,3];
For example, for first row in matrix A, The row1, row5, and row7 in Matrix B are correspondences.
I have written below code but it doesn't return back all indices which have the same row value in matrix A and only one of them (row7) is backed !!
A_sorted = sort(A,2,'descend'); % sorting angles
B_sorted = sort(B,2,'descend'); % sorting angles
[~,indx]=ismember(A_sorted,B_sorted,'rows')
the result is
indx_2 =
7
0
0
7
7
6
It means for the first row in matrix A , only one row ( row 7) in Matrix B is available !! But as you can see for first row in matrix A there is three correspondent rows in matrix B (Row 1, row 5 and row 7)

I think the best strategy is to apply ismember to unique rows
%make matrix unique
[B_unique,B2,B3]=unique(B_sorted,'rows')
[~,indx]=ismember(A_sorted,B_unique,'rows')
%For each row in B_unique, get the corresponding indices in B_sorted
indx2=arrayfun(#(x)find(B3==x),indx,'uni',0)

If you want to compare all pairs of rows between A and B, use
E = squeeze(all(bsxfun(#eq, A, permute(B, [3 2 1])), 2));
or equivalently
E = pdist2(A,B)==0;
In your example, this gives
E =
1 0 0 0 1 0 1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
1 0 0 0 1 0 1
1 0 0 0 1 0 1
0 0 0 0 0 1 0
The value E(ia,ib) tells you if the ia-th row of A equals the ib-th row of B.

Related

How to find minimum of each column in MATLAB and sum op all elements of that column?

I have a 300x178 matrix and I want to find the minimum of each column of that matrix, i.e. resulting in a 1x178 array. Then I want to store the sum of all elements but the minimum in each column in the 300x178 matrix on the location/pixel of the minimum value, leaving all other elements zero. How can I do this using MATLAB?
Example:
1 4 6 3
2 6 7 4
5 1 5 7
becomes:
1 0 0 1
0 0 0 0
0 1 1 0
and eventually:
8 0 0 14
0 0 0 0
0 11 18 0
Your example and title do not correspond to the question text. Your example sums all values in a column and stores them at the location of the minimum, which the title also asks. You can do this by making smart use of sub2ind:
A = [1 4 6 3
2 6 7 4
5 1 5 7];
C = zeros(size(A));
[tmp, idx] = min(A); % find the locations of minima
% one liner to store the sum of columns
C(sub2ind(size(A), idx, 1:size(A,2))) = sum(A,1);
C =
8 0 0 14
0 0 0 0
0 11 18 0
If, on the other hand, you're after what your question text asks about, subsequently subtract A on the minimum locations using the same sub2ind trick:
C(sub2ind(size(A), idx, 1:size(A,2))) = C(sub2ind(size(A), idx, 1:size(A,2))) - A(sub2ind(size(A), idx, 1:size(A,2)))
C =
7 0 0 11
0 0 0 0
0 10 13 0
This way you get the sum of all elements but the minimum.
For an in-depth explanation what sub2ind does, read this fantastic Q/A by Luis Mendo keeping in mind that in A(2,3) the 2 and 3 are called subscripts, which, in case of a 3-by-4 matrix, translates to linear index 8.
I cannot test this on my R2007b, but according to the documentation on min you could use [M, I] = min(A, [], 1, 'linear') to get the linear indices into I directly, without going through sub2ind:
C = zeros(size(A));
[tmp, idx] = min(A, [], 1, 'linear');
C(idx) = sum(A, 1);
% Optional, to sum all but the minimum
C(idx) = C(idx) - A(idx);
Small note from the documentation on the occurrence of multiple same-valued minima in your original matrix:
If the smallest element occurs more than once, then I contains the index to the first occurrence of the value.

Rearranging the non zero entries in a tensor into a matrix

I have a NxNx5 array T that I would like to convert into a Rx5 array TT such that the following condition is satisfied (where R is the number of non-zero entries of the array T(:,:,1)):
If T(i,j,1) == 0 then we ignore. If T(i,j,1) != 0 then I would like a row of TT whose entry is
[T(i,j,1) T(i,j,2) T(i,j,3) T(i,j,4) T(i,j,5)]
Note that T(i,j,k) (k = 2,3,4,5) could be zero. For example,
If
T(3,2,1) = 3
then I would like a row of TT to be
[3 0 2 1 5].
Some notes:
The entries of TT are all integers.
The entries accent in order column wise. i.e the first column of TT(:,:,1) maybe
[1 2 0 0 3 4 0 0 0 5 6]'
then the next column
[7 8 0 0 0 0 0 9 10 11 12]'
I think this does what you want:
ind = find(T(:,:,1));
ind = bsxfun(#plus, ind(:), (0:size(T,3)-1)*size(T,1)*size(T,2));
result = T(ind);
This will do it:
clear
rng(343)
N=7;
K=5;
T=randi([0,4],[N,N,K])
TT=reshape(T,[N*N,K])
TT(T(:,1)==0,:)=[] %delete rows with first col equal to 0

How do I randomly shuffle a subset of the elements of an existing matrix in Matlab? [duplicate]

This question already has answers here:
shuffle matrix element in matlab
(2 answers)
Closed 5 years ago.
I have a matrix of values ranging from 0 to 3 in Matlab. I want to randomly shuffle the elements of the matrix, but only within the cells that have values in the range 1 -3 (so only within a subset of the whole matrix). Is there a way to do that? Thanks.
You can do this by getting an index of all the values of interest (such as a logical index), randomly permuting their order using randperm, then assigning them back into the matrix using the same index:
% Sample matrix with values from 0 to 3:
M = randi([0 3], 5)
M =
3 1 0 3 0
0 3 3 2 0
1 0 2 1 0
1 1 2 2 0
3 0 0 1 0
index = (M > 0); % Index of values from 1 to 3
values = M(index); % Vector of indexed values
M(index) = values(randperm(numel(values))) % Matrix with shuffled values
M =
2 3 0 2 0
0 3 1 1 0
2 0 3 3 0
1 1 2 1 0
3 0 0 1 0
Note that the zeroes are all still in the same place in the shuffled matrix. Note also that you still have the same number of ones, twos, and threes, since they are just shuffled to different spots.

Inserting columns to a matrix in Matlab

I'd like to insert columns to a matrix, but the insertion column positions within the matrix differ by row. How can I do this without using for-loop?
Following is a simplified example in MATLAB;
From A,X,P, I want to get APX without using for-loop.
>> A = zeros(4,5) % inclusive matrix
A =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
>> X = [9,8;5,7;8,3;6,7] % data to insert
X =
9 8
5 7
8 3
6 7
>> P = [3;2;4;1] % insertion position within the matrix
P =
3
2
4
1
>> APX = [0,0,9,8,0;0,5,7,0,0;0,0,0,8,3;6,7,0,0,0] % what I want
APX =
0 0 9 8 0
0 5 7 0 0
0 0 0 8 3
6 7 0 0 0
It's simply determining the right column-major indices to access the matrix so you can populate it with your desired values. This first requires generating the right row and column values to access the right positions in APX so you can use X to populate those positions.
Using P, each element tells you which column you should start populating for each row of X. You will need to generate column indices in increasing order up to as many columns as there are in X. To generate the row indices, simply create a matrix that is the same size as X where each column spans from 0 up to as many rows as there are in X minus 1 (i.e. 0:size(X,2)-1). This matrix gives you the correct offsets so that you can take P and add it with this matrix. Once you do that you will have a column index matrix that tells you specifically where each element should go with regards to the columns of the output matrix per row of P. Finally, use sub2ind to generate the column-major indices using the rows and columns generated above to place X in APX.
In other words:
P = [3;2;4;1];
X = [9,8;5,7;8,3;6,7];
rowInd = repmat((1:size(X,1)).', 1, size(X,2)); %'
colInd = bsxfun(#plus, P, 0:size(X,2)-1);
APX = zeros(size(X,1), max(colInd(:)));
APX(sub2ind(size(APX), rowInd, colInd)) = X;
To generate the row locations, we use repmat to create a matrix that is the same size as X where each column spans from 1 up to as many rows as X. To generate the column locations, we use bsxfun to create a matrix where each column is the vector P but increasing by 1 per column. We then create APX to be of compatible size then use sub2ind to finally populate the matrix.
With your above test inputs, we get:
APX =
0 0 9 8 0
0 5 7 0 0
0 0 0 8 3
6 7 0 0 0
Minor Note
You really should actually try using loops before trying it vectorized. Though using loops was slow in previous versions of MATLAB, MATLAB R2015b has an improved JIT engine where loops are now competitive. You should time your code using loops and ensuring that it is justifiable before switching to vectorized implementations.

How to add limited row to specific row in Matlab?

I've two matrices A is 2x9 and B is 6x3,
A= zeros(2,9)
A =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
B=round(10*rand(6,3))
B =
7 6 9
6 7 8
4 1 7
1 1 1
8 5 1
3 5 1
by using these codes I want to add first three row of matrix B to first row of A and second three rows of matrix B to second row of matrix A by using these codes :::
for i=1:6
if i<=3
x=x(y,:)
else
end
end
I tried I don't know how inside if condition
j=1; k=1;
for i=1:6 % loop over rows of B
if (j > 9) % reset your index to point to the first entry of the next row of A
k=k+1;
j=1;
end
A(k,j:j+2)=A(k,j:j+2)+B(i,:);
j=j+3;
end
If the sizes of your Matrices change you'll have to adapt the conditions and strides respectively. This is just a quick solution. I wonder if there is a more elegant way to solve this problem - there always is, when using Matlab...