【问题标题】:Fast distance calculation in scipy and numpyscipy 和 numpy 中的快速距离计算
【发布时间】:2015-10-29 18:21:51
【问题描述】:

A,B 成为((day,observation,dim)) 数组。每个数组在给定的一天包含相同数量的观测值,观测值是一个尺寸昏暗的点(即昏暗的浮点数)。对于每一天,我想计算当天AB 中所有观测值之间的空间距离。

例如:

import numpy as np
from scipy.spatial.distance import cdist

A, B = np.random.rand(50,1000,10), np.random.rand(50,1000,10)

output = []
for day in range(50):
    output.append(cdist(A[day],B[day]))

我在哪里使用scipy.spatial.distance.cdist

有没有更快的方法来做到这一点?理想情况下,我想为output 获取一个((day,observation,observation)) 数组,该数组包含每天在AB 中的观察之间的成对距离,同时以某种方式避免了几天的循环。

【问题讨论】:

  • 您可以编写一段简短、可运行的代码,而不是用文字描述您的数据。如果您这样做是为了让人们可以复制、粘贴和运行您的问题中的代码,而不会出现未定义的变量和其他问题,那么 a) 您将使您想要的输出非常清晰 b) 您更有可能得到好的答案。 Here's a recent example
  • 谢谢,我添加了用于复制和粘贴的代码
  • 谢谢 - 我认为如果“天”的数量相对于观察的数量来说很小,那么与 cdist 计算相比,Python 循环的开销将相对微不足道。
  • @YXD 是的,我应该澄清一下。我对所有三个维度都非常大的情况感兴趣。

标签: python performance numpy multidimensional-array scipy


【解决方案1】:

一种方法(尽管它需要大量内存)是巧妙地使用数组广播:

output = np.sqrt( np.sum( (A[:,:,np.newaxis,:] - B[:,np.newaxis,:,:])**2, axis=-1) )

编辑

但经过一些测试,似乎 scikit-learn 的 euclidean_distances 可能是大型数组的最佳选择。 (请注意,我已将您的循环重写为列表理解。)

这是针对每天 100 个数据点:

# your own code using cdist
from scipy.spatial.distance import cdist
%timeit dists1 = np.asarray([cdist(x,y) for x, y in zip(A, B)])

100 loops, best of 3: 8.81 ms per loop

# pure numpy with broadcasting
%timeit dists2 = np.sqrt( np.sum( (A[:,:,np.newaxis,:] - B[:,np.newaxis,:,:])**2, axis=-1) )

10 loops, best of 3: 46.9 ms per loop

# scikit-learn's algorithm
from sklearn.metrics.pairwise import euclidean_distances
%timeit dists3 = np.asarray([euclidean_distances(x,y) for x, y in zip(A, B)])
100 loops, best of 3: 12.6 ms per loop

这是每天 2000 个数据点:

In [5]: %timeit dists1 = np.asarray([cdist(x,y) for x, y in zip(A, B)])
1 loops, best of 3: 3.07 s per loop

In [7]: %timeit dists3 = np.asarray([euclidean_distances(x,y) for x, y in zip(A, B)])

1 loops, best of 3: 2.94 s per loop

【讨论】:

  • 谢谢!我原以为 scikit 距离只是 scipy 距离的包装,但显然它们不是。
【解决方案2】:

编辑:我是个白痴,忘记了 python 的 map 是懒惰地评估的。我的“更快”代码实际上并没有做任何工作!强制评估消除了性能提升。

我认为你的时间将被花在 scipy 函数中的时间所支配。无论如何,我会使用map 而不是循环,因为我认为它有点整洁,但我认为没有任何神奇的方法可以在这里获得巨大的性能提升。也许用 cython 或使用 numba 编译代码会有所帮助。

【讨论】:

  • 太棒了!我已经尝试过 numba ,它也带来了巨大的性能提升。虽然我仍然希望可能有一种直接的 numpy 方法来将输出作为数组检索(无需转换)。
  • 如果您使用的是 Python 3,map 返回一个迭代器。如果是这样,map 不会在您运行它时评估 cdist 或任何东西。尝试打印或检查output。在 Python 2 中,map 并不懒惰,对于大型 n,第二种方法稍微慢一些 :(
猜你喜欢
  • 1970-01-01
  • 2020-02-18
  • 2016-05-19
  • 2019-08-02
  • 2014-10-02
  • 2014-09-25
  • 2015-12-20
  • 2021-02-04
  • 1970-01-01
相关资源
最近更新 更多