不同形状阵列的距离计算

2024-04-19 14:46:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我不确定我的标题是好的,但基本上我有一个参考坐标,格式是(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的目的。在

从长远来看,我想用这些距离来计算真值掩模来计算箱子中的距离值。在

我不确定是我使用了错误的函数还是使用了错误的函数,我在文档中找不到任何更好的方法。在


Tags: 函数importnumpy距离标题列表格式错误
3条回答

实际上,编写自己的函数并不难做到这一点——这是我的函数,欢迎使用。在

如果您在大量点和速度问题上执行此操作,我想这个函数将在很大程度上击败基于for循环的速度解决方案-numpy被设计为在整个矩阵上执行操作时高效。在

import numpy
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)

def euclidean_distances(ref_point, co_ords_array):
    diffs = co_ords_array - ref_point
    sqrd_diffs = numpy.square(diffs)
    sum_sqrd_diffs = numpy.sum(sqrd_diffs, axis = 1)
    euc_dists = numpy.sqrt(sum_sqrd_diffs)
    return euc_dists

scipy.spatial.distance.euclideandocumentation声明,只允许1D向量作为输入。因此,必须在数组上循环,例如:

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的解决方案的评论中所述,我将发布一条关注性能的消息:

^{pr2}$

写出所有的计算可以减少单独函数调用的数量,从而减少将中间结果分配给新数组的次数。因此,对于b.shape == (20, 3)的阵列形状,它比使用hannes-wittingham的解快大约22%,对于阵列形状为 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)

但是您正在失去能够轻松更改为距离计算例行程序的灵活性。当使用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.normaxis关键字。在

这段代码将得到欧几里德规范,在许多情况下都应该有效,而且相当快,而且只有一行代码。根据需要,其他方法更有效或更灵活,我更喜欢根据所做工作发布的其他一些解决方案。在

import numpy
a = numpy.array([1,1,1])
b = numpy.random.rand(20,3)

distances = numpy.linalg.norm(a - b, axis = 1)

相关问题 更多 >