使用numpy或scipy计算两组向量之间的欧几里得距离的最快方法

5

好的,我最近发现scipy.spatial.distance.cdist命令在解决源数组和目标数组之间的完整距离矩阵时非常快速。请参考:如何使用numpy计算欧几里德距离? 当解决两个大小相等的数组之间的距离时,我想尝试复制这些性能提升。如前面的链接所示,两个单一向量之间的距离计算相对简单。我们可以采取向量:

    import numpy as np
    A=np.random.normal(size=(3))
    B=np.random.normal(size=(3))

然后使用´numpy.linalg.norm´,其中

    np.linalg.norm(A-B)

相当于
    temp = A-B
    np.sqrt(temp[0]**2+temp[1]**2+temp[2]**2)

第一种方法在大多数情况下都很好用,但是当我想知道两组向量之间的距离时,my_distance = distance_between( A[i], B[i] ) for all i 第二种解决方案非常完美。如预期的那样:

    A=np.random.normal(size=(3,42))
    B=np.random.normal(size=(3,42))     
    temp = A-B
    np.sqrt(temp[0]**2+temp[1]**2+temp[2]**2)

给我一组42个距离,它们描述了A数组的第i个元素到B数组的第i个元素之间的距离。而norm函数正确计算整个矩阵的范数,给出一个不是我想要的单一值。我希望保持这42个距离的行为方式,希望可以像使用cdist解决完整矩阵时一样快速。因此问题是,使用Python和NumPy/SciPy计算形状为(n, i)数据之间的i个距离的最有效方法是什么?谢谢,Sloan。
2个回答

3
我认为你已经基本破解了这个问题。然而,我建议将你的最后一句改为:
np.sqrt(np.sum(temp**2,0))

谢谢,我会对其进行分析并查看它能带来多少收益,我真的很希望有一种方法可以使用其中一个C库来进一步提高性能。 - SoulNibbler
1
奇怪的是,对于100万个元素,使用np.sqrt(temp[0]**2+temp[1]**2+temp[2]**2)实际上比其他方法快3倍。 - SoulNibbler
这确实是一个意外(且令人担忧)的结果...!蛇以神秘的方式工作...;-)我对此非常感兴趣,所以你想要发表一个新问题吗?还是让我来发表? - Rolf Bartstra
我会让你发布它,但我可以在问题中分享我的个人资料代码。 - SoulNibbler
@SoulNibbler FYI,我在速度问题上发布了一个新的问题,请参见https://dev59.com/7m3Xa4cB1Zd3GeqPicNb - Rolf Bartstra

0

这里是我认为最合适的两种方法的定时比较:

import timeit
In[19]:    timeit.timeit(stmt='np.linalg.norm(x-y,axis=0)', setup='import numpy as np; x,y = np.random.normal(size=(10, 100)), np.random.normal(size=(10, 100))', number=1000000)
Out[19]:   15.132534857024439

In[20]:    timeit.timeit(stmt='np.sqrt(np.sum((x-y),axis=1))', setup='import numpy as np; x,y = np.random.normal(size=(10, 100)), np.random.normal(size=(10, 100))', number=1000000)
Out[20]:   9.417887529009022

“numpy方法运行更快,这并不让我感到惊讶。我相信随着Python的不断改进,很多这些内置函数也会得到改善。”
“测试是在Anaconda Python 3.5.2版本上进行的。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接