Skip to main content
 首页 » 编程设计

python之不同形状数组的Numpy距离计算

2025年05月04日13dyllove98

不确定我的标题是否合适,但基本上我有一个引用坐标,格式为 (x,y,z),还有一个大的坐标列表/数组也采用该格式。我需要得到每个之间的欧几里得距离,所以理论上我应该能够使用 numpy 和 scipy 进行操作,例如:

import numpy, scipy.spatial.distance 
a = numpy.array([1,1,1]) 
b = numpy.random.rand(20,3) 
 
distances = scipy.spatial.distance.euclidean(b, a) 

但我没有返回数组,而是收到错误:ValueError: Input vector should be 1-D.

不确定如何解决此错误并获得我想要的结果而不必诉诸循环等,这违背了使用 Numpy 的目的。

从长远来看,我想使用这些距离来计算用于计算 bin 中的距离值的真值掩码。

我不确定我只是使用了错误的功能还是使用了错误的功能,我无法在文档中找到任何可以更好地工作的内容。

请您参考如下方法:

documentation scipy.spatial.distance.euclidean 声明,仅允许一维向量作为输入。因此,您必须像这样遍历数组:

distances = np.empty(b.shape[0]) 
for i in range(b.shape[0]): 
    distances[i] = scipy.spatial.distance.euclidean(a, b[i]) 

如果你想有一个向量化的实现,你需要自己写一个函数。或许使用具有正确签名的 np.vectorize 也能奏效,但这实际上也只是 for 循环的简写形式,因此具有与简单 for 循环相同的性能。

正如我在对 hannes wittingham 的解决方案的评论中所述,我将发布一个专注于性能的单行代码:

distances = ((b - a)**2).sum(axis=1)**0.5 

写出所有计算减少了单独函数调用的次数,从而减少了将中间结果分配给新数组的次数。因此,对于 b.shape == (20, 3) 的数组形状,它比使用 hannes wittingham 的解决方案快约 22%,对于数组形状的数组形状快约 5% b.shape == (20000, 3):

a = np.array([1, 1, 1,]) 
b = np.random.rand(20, 3) 
%timeit ((b - a)**2).sum(axis=1)**0.5 
# 5.37 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
%timeit euclidean_distances(a, b) 
# 6.89 µs ± 345 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
 
b = np.random.rand(20000, 3) 
%timeit ((b - a)**2).sum(axis=1)**0.5 
# 588 µs ± 43.2 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) 
%timeit euclidean_distances(a, b) 
# 616 µs ± 36.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 

但是您正在失去能够轻松更改为距离计算例程的灵 active 。使用 scipy.spatial.distance 模块时,您可以通过简单地调用另一个方法来更改计算路由。

为了进一步提高计算性能,您可以为您的函数使用像 numba 这样的 jit(即时)编译器:

import numba as nb 
@nb.njit 
def euc(a, b): 
    return ((b - a)**2).sum(axis=1)**0.5 

这将小型阵列的计算时间减少了大约 70%,大型阵列的计算时间减少了大约 60%。不幸的是,numba 尚不支持 np.linalg.norm 的 axis 关键字。