2016-06-12 2 views
3

У меня есть два вектора одинакового размера, например.Как найти ближайшее (ближайшее) значение внутри вектора к другому вектору?

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

Я заинтересован, чтобы найти самые близкие значения (почти равны) в два же размере векторы A & B, то есть из всех элементов в A, значение которого находится ближе всего к любому элементу B? Решение должно быть расширяемым и для любого числа (равномерного размера) векторов. Средство, способное находить самые близкие значения с группой векторов одинакового размера A, B & C. Два результирующих значения могут быть от любого из двух векторов.

Для ясности я не заинтересован в поиске ближайших значений в пределах одного вектора. Ответ сверху пример - значения 2.56 и 2.52.

ответ

4

Это работает для общего числа векторов возможно различной длины:

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 
+1

Ничего себе, хорошее решение! – edwinksl

+0

Я позаимствовал вашу идею 'blkdiag';) +1, – thewaywewalk

+0

код работает нормально. также работают на разных длинах векторов. – erbal

3

В качестве отправной точки для двух векторов с использованием 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) 

теперь вы можете поместить его в петлю и т.д.


Кстати:

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

бы эквивалентны более очевидным:

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

но я предпочел бы пойти на первое решение, избегая накладных расходов.


И, наконец, полностью векторизация подход для нескольких векторов:

%// 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) 
+0

код работает отлично для двух векторов. Как продлить его на три или более вектора? – erbal

+0

@erbal все векторы имеют одинаковую длину? – thewaywewalk

+0

да, все имеют одинаковую длину. – erbal

1

Подобно тому, как длинный комментарий, если у вас есть acc ЕСС статистики и машинного обучения Toolbox, то вы можете использовать K-ближайших соседей функции, которые имеют некоторые плюсы, как:

  1. Handling массивов разной длины, например, когда размер (A) = [M, 1] и размер (в) = [N, 1]

  2. Обработка два одномерных массивов, например, когда размер (а) = [М, д] и размер (в) = [N, д ]

  3. Обработка различных типов расстояний, например: Евклида, Городской блок, Чебычев и многие другие, и даже у вас есть собственные дистанции.

  4. Использование алгоритма KDTree для некоторого особого случая, который вызывает отличную производительность.

Хотя в вашем случае ответ от «Луис Mendo» выглядит довольно хорошо, но это не расширяемый, как то, что K-ближайших соседей функции из набора инструментов предложения.

Обновление: Пример кода

% A and B could have any Dimension, just same number of columns (signal Dimension) 
A = rand(1000,4); 
B = rand(500,4); 

% Use any distance you like, some of them are not supported for KDTreeSearcher, 
% and you should use ExhaustiveSearcher 
myKnnModel= KDTreeSearcher(A, 'Distance', 'minkowski'); 

% you can ask for many (K) Nearest Neighbors and you always have access to it for later uses 
[Idx, D] = knnsearch(myKnnModel, B, 'K',2); 

% and this is answer to your special case 
[~, idxA] = min(D(:, 1)) 
idxB = Idx(idxA) 
+0

Это кажется многообещающим. Может быть, добавить пример с двумя или тремя векторами, чтобы сделать это на самом деле ответом? –

+0

@ LuisMendo. Я обновил свой ответ с помощью примерного кода, пожалуйста, проверьте его и скажите мне, что вы думаете об этом. – eulerleibniz

+0

Это очень хорошее обобщение. Я думаю, что у вас есть 'idxB' и' idxA'swapped: он должен быть '[~, idxB] = min (D (:, 1)); idxA = Idx (idxB); 'right? Возможно также добавить, что желаемыми ближайшими векторами являются 'A (idxA, :)' и 'B (idxB, :)' –

Смежные вопросы