2010-01-26 5 views
9

Работа в Matlab У меня есть 2 вектора координат x с разной длиной. Например:Картирование 2 вектора - help toizeize

xm = [15 20 24 25 26 35 81 84 93]; 
xn = [14 22 26 51 55 59 70 75 89 96]; 

Мне нужно отобразить хт хп, или, другими словами, чтобы выяснить, какие координаты в хп ближе к хт. Поэтому, если у меня есть значения, связанные с этими координатами, я могу использовать эту карту в качестве индекса и соотнести эти значения.

Оба вектора сортируются, и в каждом векторе нет дубликатов.

Я написал простую функцию с для цикла:

function xmap = vectors_map(xm,xn) 
xmap = zeros(size(xm)); 
for k=1:numel(xm) 
    [~, ind] = min(abs(xm(k)-xn)); 
    xmap(k) = ind(1); 
end 

Для приведенного выше примера это возвращает

xmap = 
    1  2  2  3  3  3  8  9 10 

Он работает нормально, но занимает некоторое время, с длинными векторами (более 100 000 точек) ,

Какие-нибудь идеи, как векторизовать этот код?

+0

Я использую новый синтаксис в последней версии Matlab для пропуска неиспользуемой переменной. Если у вас более ранняя версия, просто замените ~ на tmp. – yuk

+1

Чтобы уточнить, вы хотите, чтобы для каждого xm [i] был указан индекс j такой, что xm [i] ближе всего к xn [j]? –

+0

Да. Хорошее резюме, спасибо. – yuk

ответ

5

Oh! Еще один вариант: поскольку вы ищете близкие соответствия между двумя отсортированными списками, вы можете проходить их оба одновременно, используя алгоритм слияния. Это должно быть O (max (длина (xm), длина (xn))) - ish.


match_for_xn = zeros(length(xn), 1); 
last_M = 1; 
for N = 1:length(xn) 
    % search through M until we find a match. 
    for M = last_M:length(xm) 
    dist_to_curr = abs(xm(M) - xn(N)); 
    dist_to_next = abs(xm(M+1) - xn(N)); 

    if dist_to_next > dist_to_curr 
     match_for_xn(N) = M; 
     last_M = M; 
     break 
    else 
     continue 
    end 

    end % M 
end % N 

EDIT: комментарий видеть @ Юк, тем выше код не совсем правильно!

+2

Отлично! Этот код дает мне более 50-кратное улучшение скорости с векторами длиной 10 000 и 1500 (!) Раз с векторами 100 000-й. Он может возвращать ошибку, если несколько последних элементов xn сопоставлены с xm (end). Я просто изменил строки 6-7 на: , если M yuk

+0

Похоже, я не могу отформатировать код в комментариях. :( – yuk

+0

Cool! Yay! Я рад, что он работает на вас! Да, это одна из забавных вещей об информатике, когда вы вдруг делаете что-то в два раза быстрее ... – rescdsk

1

Похоже, что ваши входные векторы отсортированы. Используйте бинарный поиск, чтобы найти ближайшее совпадение. Это даст вам время O (n ln n).

+0

Не могли бы вы предоставить код Matlab? – yuk

+0

Да, векторы отсортированы. – yuk

+0

Ahh, бинарный поиск! Не думал об этом. +1 – John

0

Ваши xm и xn сортированы. Если это вообще так, то вы можете сделать гораздо лучше, чем перешагнуть через весь массив.

Для каждого значения в xn будет диапазон значений, значение которого в xm будет ближе к этому числу, чем любое другое. Вычислите эти интервалы заранее, и затем вы можете последовательно проходить через оба массива.

0

Воспользовавшись сортируется, как говорит Давид, будет быстрее, так как у вас так много очков, но для справки один способ векторизации это было бы использовать meshgrid:

[X Y] = meshgrid(xn, xm); 
diffs = X - y; 
mins = min(diffs, [], 2); 

Обратите внимание, что это создаст два массива 100 000 x 100 000 в памяти, поэтому, вероятно, это возможно только для небольших наборов данных.

+0

Yeh, это занимает много памяти и намного медленнее, чем моя функция с небольшими векторами. – yuk

4

Рассмотрим векторизованную решение:

[~, xmap] = min(abs(bsxfun(@minus, xm, xn'))) 
+0

Красивая векторная графика. Благодарю. Тем не менее, он примерно в два раза медленнее, чем моя функция, а также требует больше памяти, но лучше, чем предыдущий код. – yuk

3

Самая быстрая реализация, о которой я знаю, решает эту проблему: this one (код C, который может быть скомпилирован как файл .mex, для меня это примерно в 20 раз быстрее, чем код rescdsk в принятом ответе). Удивительно, что такая общая операция не является встроенной функцией MATLAB.

+0

Спасибо. это похоже на отличное решение. – yuk