python - einsum 和距离计算

标签 python arrays numpy euclidean-distance

我已经搜索了一种解决方案,使用 einsum 确定行数不相等但列数相等的 numpy 数组的距离。我尝试了各种组合,但唯一能成功的方法是使用以下代码。我显然遗漏了一些东西,文献和众多线程并没有让我更接近解决方案。我将很高兴找到一个通用性,使得对于任意数量的目标数组,起点可以是任意数量。我只使用二维数组,无意将其扩展到其他维度。我也熟悉 pdist 和 cdist 以及其他达到我想要的解决方案的方法,但是,我只对 einsum 感兴趣,因为我想完善我的示例库。任何帮助将不胜感激。

import numpy as np
origs = np.array([[0.,0.],[1.,0.],[0.,1.],[1.,1.]])
dests = np.asarray([[4.,0.],[1.,1.],[2.,2.],[2.,3.],[0.,5.]])
for i in origs:
    d =np.sqrt(np.einsum("ij,ij->i", i-dests, i-dests))
    print("orig {}...dist: {}".format(i,d))

下面的结果就是我要找的...

orig [ 0.  0.]...dist: [ 4.          1.41421356  2.82842712  3.60555128  5.        ]
orig [ 1.  0.]...dist: [ 3.          1.          2.23606798  3.16227766  5.09901951]
orig [ 0.  1.]...dist: [ 4.12310563  1.          2.23606798  2.82842712  4.        ]
orig [ 1.  1.]...dist: [ 3.16227766  0.          1.41421356  2.23606798  4.12310563]

最佳答案

如果我正确理解了这个问题,那么在仅考虑二维数组时,您发布的 for 循环代码对我来说看起来很通用。现在,如果您希望通过一次调用 np.einsum 获得通用矢量化解决方案。 , 你可以带进来 broadcasting入戏,就这样——

d_all = np.sqrt(np.einsum('ijk->ij',(origs[:,None,:] - dests)**2))

sample 运行-

In [85]: origs = np.array([[0.,0.],[1.,0.],[0.,1.],[1.,1.]])
    ...: dests = np.asarray([[4.,0.],[1.,1.],[2.,2.],[2.,3.],[0.,5.]])
    ...: 

In [86]: for i in origs:
    ...:     d =np.sqrt(np.einsum("ij,ij->i", i-dests, i-dests))
    ...:     print(d)
    ...:     
[ 4.          1.41421356  2.82842712  3.60555128  5.        ]
[ 3.          1.          2.23606798  3.16227766  5.09901951]
[ 4.12310563  1.          2.23606798  2.82842712  4.        ]
[ 3.16227766  0.          1.41421356  2.23606798  4.12310563]

In [87]: np.sqrt(np.einsum('ijk->ij',(origs[:,None,:] - dests)**2))
Out[87]: 
array([[ 4.        ,  1.41421356,  2.82842712,  3.60555128,  5.        ],
       [ 3.        ,  1.        ,  2.23606798,  3.16227766,  5.09901951],
       [ 4.12310563,  1.        ,  2.23606798,  2.82842712,  4.        ],
       [ 3.16227766,  0.        ,  1.41421356,  2.23606798,  4.12310563]])

根据 comments by @hpaulj ,您还可以使用 np.einsum 本身执行平方,就像这样 -

subts = origs[:,None,:] - dests
d_all = np.sqrt(np.einsum('ijk,ijk->ij',subts,subts))

这是一个运行时测试,用于将此与之前在 np.einsum 之外完成的平方 方法进行比较 -

In [7]: def all_einsum(origs,dests):
   ...:     subts = origs[:,None,:] - dests
   ...:     return np.sqrt(np.einsum('ijk,ijk->ij',subts,subts))
   ...: 
   ...: def partial_einsum(origs,dests):
   ...:     return np.sqrt(np.einsum('ijk->ij',(origs[:,None,:] - dests)**2))
   ...: 

In [8]: origs = np.random.rand(400,100)

In [9]: dests = np.random.rand(500,100)

In [10]: %timeit all_einsum(origs,dests)
10 loops, best of 3: 139 ms per loop

In [11]: %timeit partial_einsum(origs,dests)
1 loops, best of 3: 251 ms per loop

关于python - einsum 和距离计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32154475/

相关文章:

python - 如何仅返回 pandas 数据框中的连续值

python - 从 django 服务器中存在的另一个 python 脚本引用当前打开的 XMPP 连接

php - 将字符串转换为字符数组

python - Scipy - 找到矩阵列空间的基础

python - matplotlib 直方图中的内存泄漏

python - 多处理池方法的性能问题

python - 如何将 `Object` 与字符串连接起来?

Java 基本数组 List.contains 无法按预期工作

c++ - 函数返回一个数组

python - Python 的 NumPy.around : Rounding NumPy Arrays 中更好的舍入