scipy和numpy中的快速距离计算

时间:2015-08-06 14:32:14

标签: python performance numpy multidimensional-array scipy

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <form> <div class="group"> <div class="choice"> <input type="radio" name="group[0][]" value="admin" /> <label>Admin</label> </div> <div class="choice"> <input type="radio" name="group[0][]" value="user" /> <label>User</label> </div> <div class="choice"> <input type="radio" name="group[0][]" value="moderator" /> <label>Moderator</label> </div> </div> <div class="group"> <div class="choice"> <input type="radio" name="group[1][]" value="admin" /> <label>Admin</label> </div> <div class="choice"> <input type="radio" name="group[1][]" value="user" /> <label>User</label> </div> <div class="choice"> <input type="radio" name="group[1][]" value="moderator" /> <label>Moderator</label> </div> </div> </form>A,B个数组。每个数组在给定的一天包含相同数量的观察值,观察值是具有暗淡维度的点(即暗淡的浮点数)。对于每一天,我想计算当天((day,observation,dim))A中所有观测值之间的空间距离。

例如:

B

我使用scipy.spatial.distance.cdist

有更快的方法吗?理想情况下,我希望获得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])) 一个output数组,该数组每天包含((day,observation,observation))A中观察值之间的成对距离,同时以某种方式避免循环过了几天。

2 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:2)

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

我认为你的时间将由scipy函数内部所花费的时间占主导地位。我总是使用map而不是循环,因为我认为它有点整洁,但我不认为有任何神奇的方法可以在这里获得巨大的性能提升。也许使用cython或使用numba编译代码会有所帮助。