согласно моему комментарию, использование abs
, вероятно, является лучшим вариантом для очистки числовой стабильности, присущей этому алгоритму. поскольку вы беспокоитесь о производительности, вам, вероятно, следует использовать изменяющиеся операторы присваивания, поскольку они создают меньше мусора и, следовательно, могут быть намного быстрее. Кроме того, при выполнении этого со многими функциями (например, 10 КБ) я вижу, что pdist
медленнее, чем эта реализация.
, сложив вышеприведенное вместе, мы получаем:
import numpy as np
def edist0(M):
"calculate pairwise euclidean distance"
M_norm = np.sum(M**2, axis=1)
res = M_norm[:, np.newaxis] + M_norm[np.newaxis, :] - 2. * M @ M.T
return np.sqrt(np.abs(res))
def edist1(M):
"optimised calculation of pairwise euclidean distance"
M_norm = np.einsum('ij,ij->i', M, M)
res = M @ M.T
res *= -2.
res += M_norm[:, np.newaxis]
res += M_norm[np.newaxis, :]
return np.sqrt(np.abs(res, out=res), out=res)
синхронизация этого в I Python с:
from scipy.spatial import distance
M = np.random.rand(1000, 10000)
%timeit distance.squareform(distance.pdist(M))
%timeit edist0(M)
%timeit edist1(M)
Я получаю:
2.82 s ± 60.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
296 ms ± 6.07 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
153 ms ± 1.58 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
и без ошибок / предупреждений от sqrt
связанный вопрос также указывает на scikit-learn as с хорошими реализациями ядра расстояния, евклидовым является pairwise_distances
, который оценивается как:
from sklearn.metrics import pairwise_distances
%timeit pairwise_distances(M)
170 ms ± 5.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
, что может быть удобно использовать, если вы уже используете этот пакет