不确定我的标题是否合适,但基本上我有一个引用坐标,格式为 (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
关键字。
关于python - 不同形状数组的Numpy距离计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51250169/