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 对于许多点和中心来说是最快的。