Python scipy和numpy中的快速距离计算

Python scipy和numpy中的快速距离计算,python,performance,numpy,multidimensional-array,scipy,Python,Performance,Numpy,Multidimensional Array,Scipy,让A,B成为((天,观察,dim))数组。对于给定的一天,每个数组都包含相同数量的观测值,一个观测值是一个具有dim维度(即dim浮动)的点。对于每一天,我想计算当天A和B中所有观测值之间的空间距离 例如: 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

A,B
成为
((天,观察,dim))
数组。对于给定的一天,每个数组都包含相同数量的观测值,一个观测值是一个具有dim维度(即dim浮动)的点。对于每一天,我想计算当天
A
B
中所有观测值之间的空间距离

例如:

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]))
我用的地方


有没有更快的方法?理想情况下,我希望为
输出
a
((天,观察,观察))
数组,该数组每天包含
a
B
中观察值之间的成对距离,同时不知何故避免了几天内的循环。

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

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

一种方法是巧妙地利用阵列广播:

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

编辑

但经过一些测试,似乎scikit learn是大型阵列的最佳选择。(请注意,我已将您的循环改写为列表。)

这是针对每天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
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
这是针对每天2000个数据点:

# 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
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

您可以编写一段简短、可运行的代码,而不是用文字描述数据。如果你这样做是为了让人们能够复制、粘贴和运行你问题中的代码,而没有未定义的变量和其他问题,那么a)你将使你想要的输出非常清晰,b)你更有可能得到好的答案。谢谢,我为复制和粘贴添加了代码谢谢-我认为如果“天”的数量相对于观察的数量来说很小,那么与
cdist
计算相比,Python循环的开销将相对较小。@YXD是的,我应该澄清一下。我对三个维度都非常大的情况很感兴趣。太棒了!我已经尝试过numba,它也大大提高了性能。尽管我仍然希望有一种直接的numpy方法可以以数组的形式检索输出(无需转换)。如果是这样,
map
在运行它时不会计算
cdist
或任何东西。尝试打印或检查
输出
。在Python2中,
map
并不懒惰,第二种方法对于较大的
n
稍微慢一些:(谢谢!我本以为scikit距离只是scipy距离的包装,但显然不是。