Matlab: евклидова норма (или разница) между двумя векторами - PullRequest
0 голосов
/ 19 ноября 2018

Я хотел бы рассчитать евклидово расстояние между вектором G и каждой строкой массива C, при этом разделив каждую строку на значение в векторе GSD.То, что я сделал, кажется очень неэффективным.Какие мои самые большие накладные расходы?Могу ли я ускорить это?

m=1E7;
G=1E5*rand(1,8);
C=1E5*[zeros(m,1),rand(m,8)]; 
GSD=10*rand(1,8);

%I've taken the log10 of the values because G and C are very large in magnitude. 
%Don't know if it's worth it.

for i=1:m
    dG(i,1)=norm((log10(G)-log10(C(i,2:end)))/log10(GSD));
end

Используя приведенные ниже примеры, они не все дают одинаковый ответ.Фактически, ни один из них не дает такой же ответ (см. Следующий рисунок, используя:

dG = pdist2(log10(G),log10(C(:,2:end)),'mahalanobis',diag(log10(GSD))); %(1)

dG = sqrt(sum((log10(G)-log10(C(:,2:end))./log10(GSD)).^2,2)); 

tmp=bsxfun(@rdivide,bsxfun(@minus,log10(G),log10(C(:,2:end))),log10(GSD)); %(4)
dG = sqrt(sum(tmp.^2,2));

enter image description here

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Плавающая точка должна обрабатывать большую величину входных данных, вплоть до определенной точки с данными float и с любым разумным значением с double данными

realmax('single')
ans =
  3.4028e+38

realmax('double')
ans =
  1.7977e+308

При значениях 1e7 в диапазоне +/- 1e5 вы можете ожидать, что квадрат евклидова расстояния будет находиться в диапазоне +/- 1e17 (5 + 5 + 7), который оба формата будут легко обрабатывать.

В любом случае, вы должны векторизовать код для удаления цикла (который Matlab имеет историю обработки очень неэффективно, особенно в старых версиях)

В новых версиях (2016b и новее) просто используйте:

tmp=(log10(G)-log10(C(:,2:end)))./log10(GSD);
dG = sqrt(sum(tmp.^2,2)); %row-by-row norm

Обратите внимание, что вы должны использовать ./, который является поэлементным делением, а не /, который является матричным правым делением.

Следующий код будет работать везде

tmp=bsxfun(@rdivide,bsxfun(@minus,log10(G),log10(C(:,2:end))),log10(GSD));
dG = sqrt(sum(tmp.^2,2)); %row-by-row norm

Я, однако, считаю, что использование log10 является математической ошибкой. Результат dG не будет евклидовой нормой. Вы должны придерживаться среднеквадратичного значения взвешенной разницы:

dG = sqrt(sum(bsxfun(@rdivide,bsxfun(@minus,G,C(:,2:end)),GSD).^2,2)); % all versions
dG = sqrt(sum((G-C(:,2:end)./GSD).^2,2)); %R2016b and later
0 голосов
/ 19 ноября 2018

Вы можете использовать pdist2(x,y) для вычисления попарного расстояния между всеми элементами в x и y, таким образом, ваш пример будет выглядеть примерно так:

dG = pdist2(log10(G),log10(C(:,2:end)),'mahalanobis',diag(log10(GSD)).^2);

, гдеname-pair 'mahalanobis',diag(log10(GSD)).^2 помещает log10(GSD) в качестве весов на Евклиде, известную как расстояние Махаланобиса.

Обратите внимание, что расстояние Махаланобиса изначально предназначено для нормализации данных, поэтому именно «ковариация» должна быть указана в качестве четвертого входа, и MATLAB затем находит разложение Холецкого (поэлементный квадратный корень при диагонали, как здесь).

Неявное расширение

В более новых выпусках MATLAB также можно просто использовать расширение implcit, поскольку первая запись содержит только 1 вектор.

dG = sqrt(sum(((log10(G)-log10(C(:,2:9)))./log10(GSD)).^2,2));

, что, вероятно, немного быстрее, однако я предпочитаю решение pdist2, так как оно мне яснее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...