Numpy решение:
Numpy велик с вещания, так что вы можете обмануть его, чтобы сделать все расстояния в один шаг. Но он будет потреблять много памяти в зависимости от количества точек и кластерных центров. Фактически он создаст массив number_of_points * number_of_cluster_centers * 3
:
Сначала вам нужно немного узнать о вещании, я сыграю его сам и определю каждое измерение вручную.
Я начну с определения некоторых точек и центров для целей иллюстрации:
import numpy as np
points = np.array([[1,1,1],
[2,1,1],
[1,2,1],
[5,5,5]])
centers = np.array([[1.5, 1.5, 1],
[5,5,5]])
Теперь я буду готовить эти массивы так, что я могу использовать Numpy вещания, чтобы получить расстояние в каждом измерении:
distance_3d = points[:,None,:] - centers[None,:,:]
Эффект. Первое измерение теперь означает «метка», второе измерение - это «метка» центров, а третье измерение - координата. Вычитание состоит в том, чтобы получить расстояние в каждом измерении. Результат будет иметь форму:
(number_of_points, number_of_cluster_centers, 3)
теперь это только вопрос применения формулы евклидового расстояния:
# Square each distance
distance_3d_squared = distance_3d ** 2
# Take the sum of each coordinates distance (the result will be 2D)
distance_sum = np.sum(distance_3d_squared, axis=2)
# And take the square root
distance = np.sqrt(distance_sum)
Для моих тестовых данных конечного результата является:
#array([[ 0.70710678, 6.92820323],
# [ 0.70710678, 6.40312424],
# [ 0.70710678, 6.40312424],
# [ 6.36396103, 0. ]])
Таким образом, элемент distance[i, j]
даст вам расстояние от i
до центра j
.
Резюме:
Вы можете поместить все это в одной строке:
distance2 = np.sqrt(np.sum((points[:,None,:] - centers[None,:,:]) ** 2, axis=2))
раствора SciPy (быстрее & короче):
или если у вас есть SciPy использование cdist
:
from scipy.spatial.distance import cdist
distance3 = cdist(points, centers)
Результат всегда будет таким же, но cdist
является самым быстрым для множества точек и центров.
Загляните в 'cdist' из' scipy'. – Divakar