以下用例:
我有一个Numpy矩阵/数组,有几千个2d点。称之为A. 例如:
[1 2]
[300 400]
..
[123 242]
我还有另一个Numpy矩阵,上面有几个2d点。称之为B
。
基本上,我想迭代A
,然后遍历B
并计算A[i]
和B[j]
之间的距离。然后将其分配回另一个数组。我可以这样做:
for i, (x0, x1) in enumerate(zip(A[:,0],A[:,1])):
weight_distance = 0
for j, (p0, p1) in enumerate(zip(A[:,0],A[:,1])):
weight_distance = weight_distance + distance((p0,p1),(x0,x1))
weight_array[i] = weight_distance
但这太慢了。什么可能是Numpy方法来解决这个问题?
答案 0 :(得分:0)
您可能正在寻找的是scipy.spatial.distance
中的代码,尤其是cdist函数。这可以有效地计算各种度量的点阵列之间的成对距离。
import numpy as np
from scipy.spatial.distance import cdist
A = np.random.random((1000, 2))
B = np.random.random((100, 2))
D = cdist(A, B, metric='euclidean')
print(D.shape) # (1000, 100)
weights = D.sum(1)
print(weights.shape) # (1000,)
此处euclidean
是您可能习惯的标准根和平方距离,D[i, j]
保持A[i]
和B[j]
之间的距离,所以沿轴1求和得到所需的权重。
有很多方法可以通过直接在numpy中进行广播来实现,但是这种方法会使用几个大的临时数组,并且通常比scipy cdist
方法慢。
编辑: 我想我也可以在仅限NumPy的方法上添加一个注释。它看起来像这样:
D2 = np.sqrt(((A[:, None, :] - B[None, :, :]) ** 2).sum(-1))
weights2 = D2.sum(1)
np.allclose(weights, weights2) # True
让我们分解一下:
A[:, None, :]
为A
添加了一个新维度,因此其形状现为[1000, 1, 2]
。与B[None, :, :]
类似,后者变为[1, 100, 2]
A[:, None, :] - B[None, :, :]
是一种广播操作,会产生一系列差异,形状为[1000, 100, 2]
sum(-1)
方法在最后一个维度上求和,从而生成一个形状[1000, 100]
的数组请注意,这种广播方法在此过程中不会创建一个大小为1000 * 100 * 2
的两个临时数组,这就是为什么它比专用的编译函数(如{)效率低的原因。 {1}}。