Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find closest (nearest) value within a vector to another vector?

I have two equal sized vectors, e.g.

A=[2.29 2.56 2.77 2.90 2.05] and
B=[2.34 2.62 2.67 2.44 2.52].

I am interested to find closest values (almost equal) in two same size vectors A & B, i.e. out of all elements in A, which value is closest to any element of B? The solution should be extendable to any number of (equal size) vectors also. Means able to find closest values with a group of same sized vectors A,B &C. The two resulting values can be from either of two vectors.

For clarity, i am not interested to find closest values within a single vector. The answer from above example is values 2.56 and 2.52.

like image 813
erbal Avatar asked Jan 25 '26 09:01

erbal


2 Answers

This works for a generic number of vectors of possibly different lengths:

vectors = {[2.29 2.56 2.77 2.90 2.05] [2.34 2.62 2.67 2.44 2.52] [1 2 3 4]}; 
    % Cell array of data vectors; 3 in this example
s = cellfun(@numel, vectors); % Get vector lengths
v = [vectors{:}]; % Concatenate all vectors into a vector
D = abs(bsxfun(@minus, v, v.')); % Compute distances. This gives a matrix.
    % Distances within the same vector will have to be discarded. This will be
    % done by replacing those values with NaN, in blocks
bb = arrayfun(@(x) NaN(x), s, 'uniformoutput', false); % Cell array of blocks
B = blkdiag(bb{:}); % NaN mask with those blocks
[~, ind] = min(D(:) + B(:)); % Add that mask. Get arg min in linear index
[ii, jj] = ind2sub(size(D), ind); % Convert to row and column indices
result = v([ii jj]); % Index into concatenated vector
like image 162
Luis Mendo Avatar answered Jan 26 '26 23:01

Luis Mendo


As a starting point for two vectors using bsxfun:

%// data
A = [2.29 2.56 2.77 2.90 2.05]
B = [2.34 2.62 2.67 2.44 2.52]

%// distance matrix 
dist = abs(bsxfun(@minus,A(:),B(:).'));

%// find row and col indices of minimum
[~,idx] = min(dist(:))
[ii,jj] = ind2sub( [numel(A), numel(B)], idx)

%// output 
a = A(ii)
b = B(jj)

now you can put it into a loop etc.


By the way:

dist = abs(bsxfun(@minus,A(:),B(:).'));

would be equivalent to the more obvious:

dist = pdist2( A(:), B(:) )

but I'd rather go for the first solution avoiding the overhead.


And finally the fully vectorized approach for multiple vectors:

%// data
data{1} = [2.29 2.56 2.77 2.90 2.05];
data{2} = [2.34 2.62 2.67 2.44 2.52];
data{3} = [2.34 2.62 2.67 2.44 2.52].*2;
data{4} = [2.34 2.62 2.67 2.44 2.52].*4;
%// length of each vector
N = 5;

%// create Filter for distance matrix
nans(1:numel(data)) = {NaN(N)};
mask = blkdiag(nans{:}) + 1; 

%// create new input for bsxfun
X = [data{:}];

%// filtered distance matrix 
dist = mask.*abs(bsxfun(@minus,X(:),X(:).'));

%// find row and col indices of minimum
[~,idx] = min(dist(:))
[ii,jj] = ind2sub( size(dist), idx)

%// output 
a = X(ii)
b = X(jj)
like image 30
Robert Seifert Avatar answered Jan 26 '26 23:01

Robert Seifert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!