1

In my application, I need to find the "closest" (minimum Euclidean distance vector) to an input vector, among a set of vectors (i.e. a matrix)

Therefore every single time I have to do this :

function [match_col] = find_closest_column(input_vector, vectors)
cmin = 99999999999; % current minimum distance
match_col = -1;    

    for col=1:width
        candidate_vector = vectors(:,c); % structure of the input is not important
        dist = norm(input_vector - candidate_vector);
        if dist < cmin
            cmin = dist;
            match_col = col;
        end
    end

is there a built-in MATLAB function that does this kind of thing easily (with a short amount of code) for me ?

Thanks for any help !

jeff
  • 13,055
  • 29
  • 78
  • 136
  • possible duplicate of [how to find the closest vector to a given vector in matlab?](http://stackoverflow.com/questions/10639925/how-to-find-the-closest-vector-to-a-given-vector-in-matlab) – Rafael Monteiro Apr 19 '14 at 15:43

2 Answers2

4

Use pdist2. Assuming (from your code) that your vectors are columns, transposition is needed because pdist2 works with rows:

[cmin, match_col] = min(pdist2(vectors.', input_vector.' ,'euclidean'));

It can also be done with bsxfun (in this case it's easier to work directly with columns):

[cmin, match_col] = min(sum(bsxfun(@minus, vectors, input_vector).^2));
cmin = sqrt(cmin); %// to save operations, apply sqrt only to the minimizer 
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • Thank you very much ! I actually don't need the cmin value. I only need `match_col`. and what is the `@minus` operator doing? If it was `@plus`, then would it return the far-est vector ? – jeff Apr 20 '14 at 18:59
  • The `@minus` is just the minus sign that you use in computing the Euclidean distance (within each square term). To find the farthest vector, change `min` to `max` (keeping `@minus`) – Luis Mendo Apr 20 '14 at 20:14
  • Ok, I don't have time to try now but I trust this is the correct answer. Thanks again ! – jeff Apr 20 '14 at 21:15
3

norm can't be directly applied to every column or row of a matrix, so you can use arrayfun:

dist = arrayfun(@(col) norm(input_vector - candidate_vector(:,col)), 1:width);
[cmin, match_col] = min(dist);

This solution was also given here.

HOWEVER, this solution is much much slower than doing a direct computation using bsxfun (as in Luis Mendo's answer), so it should be avoided. arrayfun should be used for more complex functions, where a vectorized approach is harder to get at.

Community
  • 1
  • 1
buzjwa
  • 2,632
  • 2
  • 24
  • 37
  • +1 But take into account that [`arrayfun` may not be the fastest approach](http://stackoverflow.com/questions/12522888/arrayfun-can-be-significantly-slower-than-an-explicit-loop-in-matlab-why) – Luis Mendo Apr 19 '14 at 16:03
  • Yes exactly what I wrote you. So should I delete this? – buzjwa Apr 19 '14 at 16:04
  • It's not the fastest approach, but I don't think it should be necessarily deleted. – Luis Mendo Apr 19 '14 at 16:06
  • 1
    I edited it with a warning and your link, so it's clear this should not be the solution of choice. – buzjwa Apr 19 '14 at 16:12