Евклидово расстояние между двумя точками с использованием векторизованного подхода

#python #numpy #scikit-learn

Вопрос:

У меня есть два больших numpy массива, для которых я хочу рассчитать евклидово расстояние, используя sklearn . Следующий MRE достигает того, что я хочу в конечном результате, но, поскольку мое использование RL велико, мне действительно нужно векторизованное решение, а не использование for цикла.

 import numpy as np
from sklearn.metrics.pairwise import euclidean_distances

n = 3
sample_size = 5

X = np.random.randint(0, 10, size=(sample_size, n))
Y = np.random.randint(0, 10, size=(sample_size, n))

lst = []

for f in range(0, sample_size):
    ed = euclidean_distances([X[f]], [Y[f]])
    lst.append(ed[0][0])

print(lst)
 

Комментарии:

1. Вы указали, что хотите использовать sklearn для вычисления расстояний. Это действительно необходимо? Если это так, то я думаю, что вы застряли с тем, что они вам дали. Если нет, то непонятно, в чем проблема будет заключаться в написании вашего собственного, как вы хотите. Евклидово расстояние не является сложной функцией.

2. Возможно, я неправильно истолковываю то, чего вы пытаетесь достичь, но euclidean_distances(X, Y).diagonal() не делаете то, что вы хотите? Если нет, не могли бы вы объяснить, чем это отличается от того, чего вы хотите?

3. np.sqrt(((X - Y)**2).sum(1)) ?

4. @Brick да, я знаю, это для онлайн-класса, и поэтому я предполагаю, что мы будем опираться на его сложность.

5. @Брайан: это работает! Можете ли вы отправить сообщение в качестве ответа, и я приму его?

Ответ №1:

euclidean_distances вычисляет расстояние для каждой комбинации точек X,Y; это увеличит объем памяти и совершенно не нужно, если вам просто нужно расстояние между каждой соответствующей строкой. Sklearn включает в себя другую функцию, paired_distances которая делает то, что вы хотите:

 from sklearn.metrics.pairwise import paired_distances
d = paired_distances(X,Y)
# array([5.83095189, 9.94987437, 7.34846923, 5.47722558, 4.        ])
 

Если вам нужны полные попарные расстояния, вы можете получить тот же результат по диагонали (как указано в комментариях).:

 d = euclidean_distances(X,Y).diagonal()
 

Наконец: массивы относятся к типу numpy, поэтому полезно знать сам api numpy (prob. то, что склирн называет «под капотом»). Вот два примера:

 d = np.linalg.norm(X-Y, axis=1)
d = np.sqrt(np.sum((X-Y)**2, axis=1))