Matlab - Finding values within a matrix - matlab

How can I find the row that have all the values from A into the matrix B and display the index of the rows using Matlab?
A= [2 5 6];
B=[1 2 4 9 10 15 27 30;
1 2 3 4 5 6 7 8;
1 2 3 5 6 9 22 101;
2 4 5 6 14 20 22 23]
Thanks

With bsxfun in 3D -
ind = find(all(any(bsxfun(#eq,B,permute(A,[1 3 2])),2),3))
With bsxfun again, but keeping it in 2D -
ind = find(sum(reshape(any(bsxfun(#eq,B(:),A(:).'),2),size(B)),2)==numel(A))
With ismember -
ind = find(sum(reshape(ismember(B(:),A(:)),size(B)),2)==numel(A))
With pdist2 from Statistics and Machine Learning Toolbox -
ind = find(sum(reshape(any(pdist2(B(:),A(:))==0,2),size(B)),2)==numel(A))
With knnsearch again from Statistics and Machine Learning Toolbox-
[~,dists] = knnsearch(A(:),B(:))
ind = find(sum(reshape(dists==0,size(B)),2)==numel(A))
Sample run -
A =
2 5 6
B =
1 2 4 9 10 15 27 30
1 2 3 4 5 6 7 8
1 2 3 5 6 9 22 101
2 4 5 6 14 20 22 23
ind =
2
3
4

Related

If A is a vector subset of B, how can I find the indices of A within B in MATLAB?

Consider a row vector A and row vector B. For example:
A = [1 2 3 7 8 10 12];
B = [1 1 2 2 2 3 5 6 6 7 7 7 8 8 10 10 10 11 12 12 12 13 15 16 18 19];
A has previously been checked to be a subset of B. By subset, I specifically mean that all elements in A can be found in B. I know that elements in A will not ever repeat. However, the elements in B are free to repeat as many or as few times as they like. I checked this condition using:
is_subset = all(ismember(A,B));
With all that out of the way, I need to know the indices of the elements of A within B including the times when these elements repeat within B. For the example A and B above, the output would be:
C = [1 2 3 4 5 6 10 11 12 13 14 15 16 17 19 20 21];
Use ismember to find the relevant logical indices. Then convert them to linear indices using find.
C = find(ismember(B,A));
You can find the difference of each element of A with B, and get the indices you want. Something like below:
A = [1 2 3 7 8 10 12];
B = [1 1 2 2 2 3 5 6 6 7 7 7 8 8 10 10 10 11 12 12 12 13 15 16 18 19];
C = [1 2 3 4 5 6 10 11 12 13 14 15 16 17 19 20 21];
tol = 10^-3 ;
N = length(A) ;
iwant = cell(N,1) ;
for i = 1:N
idx = abs(A(i)-B)<=tol ;
iwant{i} = find(idx) ;
end
iwant = [iwant{:}] ;

Reshaping vector to n-d matrix in row-wise order

I'm trying to convert a vector into a 3d matrix in a row-wise manner.
For example, my vector is:
a = 1:18;
and I'd like to convert this to a 2x3x3 matrix:
b(:,:,1) = [1 2 3; 4 5 6];
b(:,:,2) = [7 8 9; 10 11 12];
b(:,:,3) = [13 14 15; 16 17 18];
but the reshape function (i.e. reshape(a, 2,3,3)) arranges the elements in a column-wise fashion as:
val(:,:,1) =
1 3 5
2 4 6
val(:,:,2) =
7 9 11
8 10 12
val(:,:,3) =
13 15 17
14 16 18
How can I obtain the matrix b from vector a?
Use combination of reshape and permute.
b = permute(reshape(a,3,2,3),[2 1 3]);
b(:,:,1) =
1 2 3
4 5 6
b(:,:,2) =
7 8 9
10 11 12
b(:,:,3) =
13 14 15
16 17 18
I found a (or the) solution:
b = permute(reshape(reshape(a,3,[])',2,3,[]), [1,3,2])
b(:,:,1) =
1 2 3
4 5 6
b(:,:,2) =
7 8 9
10 11 12
b(:,:,3) =
13 14 15
16 17 18

How to separately compute the Euclidean Distance in different dimension?

I got a question when using pdist, it would be so many thanks if you could give me some advice. The pdist(D) usually gives the sum of the distance for the multiple dimension, however, I want to get the distance separately. For example I have a data set S which is a 10*2 matrix , I am using pdist(S(:,1)) and pdist(S(:,2)) to get the distance separately, but this seems very inefficient when the data has many dimensions. Is there any alternative way to achieve this more efficient? Thanks in advance!
Assuming you just want the absolute difference between the individual dimensions of the points then pdist is overkill. You can use the following simple function
function d = pdist_1d(S)
idx = nchoosek(1:size(S,1),2);
d = abs(S(idx(:,1),:) - S(idx(:,2),:));
end
which returns the absolute pairwise difference between all pairs of rows in S.
In this case
dist = pdist_1d(S)
gives the same result as
dist = cell2mat(arrayfun(#(dim)pdist(S(:,dim))',1:size(S,2),'UniformOutput',false));
Another option, since you're simply taking the absolute difference of the coordinates, is to use bsxfun:
>> D = randi(20, 10, 2) % generate sample data
D =
17 12
14 10
8 4
7 11
19 13
2 18
11 14
5 19
19 12
20 8
From here, we permute the data so that the coordinates (columns) extend into the 3rd dimension and the rows are in the 1st dimension for the 1st argument, and the 2nd dimension for the 2nd argument:
>> dist = bsxfun(#(x,y)abs(x-y), permute(D, [1 3 2]), permute(D, [3 1 2]))
dist =
ans(:,:,1) =
0 3 9 10 2 15 6 12 2 3
3 0 6 7 5 12 3 9 5 6
9 6 0 1 11 6 3 3 11 12
10 7 1 0 12 5 4 2 12 13
2 5 11 12 0 17 8 14 0 1
15 12 6 5 17 0 9 3 17 18
6 3 3 4 8 9 0 6 8 9
12 9 3 2 14 3 6 0 14 15
2 5 11 12 0 17 8 14 0 1
3 6 12 13 1 18 9 15 1 0
ans(:,:,2) =
0 2 8 1 1 6 2 7 0 4
2 0 6 1 3 8 4 9 2 2
8 6 0 7 9 14 10 15 8 4
1 1 7 0 2 7 3 8 1 3
1 3 9 2 0 5 1 6 1 5
6 8 14 7 5 0 4 1 6 10
2 4 10 3 1 4 0 5 2 6
7 9 15 8 6 1 5 0 7 11
0 2 8 1 1 6 2 7 0 4
4 2 4 3 5 10 6 11 4 0
This results in a 3-d symmetric matrix where
dist(p, q, d)
gives you the distance between points p and q in dimension d with
dist(p, q, d) == dist(q, p, d)
If you want the distances between p and q in all (or multiple) dimensions, you should use squeeze to put it in a vector:
>> squeeze(dist(3, 5, :))
ans =
11
9
Note that if you're using MATLAB 2016b or later (or Octave) you can create the same distance matrix without bsxfun:
dist = abs(permute(D, [1 3 2]) - permute(D, [3 1 2]))
The downside to this approach is that it creates the full symmetric matrix so you're generating each distance twice, which could potentially become a memory issue.

Sorting every layer of 3D matrix by one column each

I have a 3D matrix. Say it is:A = randi(15,[4,3,2]). I want to sort the 2nd column of each layer in an ascending order, but the other columns simply stayed in their respective rows. How can I do that?
If the two layers are like this
val(:,:,1) =
6 12 13
10 14 8
15 8 2
4 3 14
val(:,:,2) =
10 1 8
2 15 12
14 11 1
1 6 11
Then I want a result like this
val(:,:,1) =
4 3 14
15 8 2
6 12 13
10 14 8
val(:,:,2) =
10 1 8
1 6 11
14 11 1
2 15 12
If you have the Image Processing Toolbox, using blockproc is one solution:
val(:,:,1) = [ ...
6 12 13
10 14 8
15 8 2
4 3 14]
val(:,:,2) = [ ...
10 1 8
2 15 12
14 11 1
1 6 11]
%// row indices to used for sorting
rowidx = 2;
[n,m,p] = size( val );
%// get a 2D matrix
val2D = reshape(val, n, [], 1)
%// sorting
out2D = blockproc(val2D,[n,m],#(x) sortrows(x.data,rowidx))
%// transform back to 3D
out3D = reshape(out2D, n, m, [])
Without the toolbox, maybe a little slower:
temp = arrayfun(#(x) sortrows(val(:,:,x),rowidx),1:size(val,3),'uni',0)
out3D = cat(3,temp{:})
out3D(:,:,1) =
4 3 14
15 8 2
6 12 13
10 14 8
out3D(:,:,2) =
10 1 8
1 6 11
14 11 1
2 15 12

Getting all submatrices

I have got an N×M matrix m like:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
I want to get all submatrices of size P×Q (P,Q are odd) w/o employing a for-loop.
The result s should be a P×Q×((N-P+1)·(M-Q+1)) matrix.
E.g. if P=Q=3:
s(:,:,1) = [1 2 3; 5 6 7; 9 10 11]
s(:,:,2) = [2 3 4; 6 7 8; 10 11 12]
s(:,:,3) = [5 6 7; 9 10 11; 13 14 15]
s(:,:,4) = [6 7 8; 10 11 12; 14 15 16]
im2col can help you out here:
m =
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
>> P = 3; Q = 3;
>> columnized = im2col(m,[P Q],'sliding');
>> nMatrices = size(columnized,2);
>> s = reshape(columnized, [P Q nMatrices])
s(:,:,1) =
1 2 3
5 6 7
9 10 11
s(:,:,2) =
5 6 7
9 10 11
13 14 15
s(:,:,3) =
2 3 4
6 7 8
10 11 12
s(:,:,4) =
6 7 8
10 11 12
14 15 16
im2col with the 'sliding' option finds all the overlapping submatrices and returns each as a (P·Q)-element column vector in columnized. To turn these back into matrices, we reshape this (P·Q)×((N-P+1)·(M-Q+1)) matrix into a P×Q×((N-P+1)·(M-Q+1)) one.