【问题标题】:Calculate Euclidean distance on numpy row-row cross product?计算numpy行行叉积的欧几里得距离?
【发布时间】:2020-08-07 11:56:20
【问题描述】:

我有两个带有 n 坐标数的 numpy 数组(每行两个项目)。

coords_a = np.random.random((20, 2))
coords_b = np.random.random((20, 2))

现在,对于每个行组合,我想计算一个函数并将返回值保存为矩阵中的项。因此,生成的数组应该具有(20, 20) 的形状,并且可以“惰性”计算,如下所示。作为示例函数,使用了欧几里得距离。

def euclidean_dist(x1: float, y1: float, x2: float, y2: float) -> float:
    """Return the euclidean distance between two the points (x1, y1) and (x2, y2)."""
    return np.sqrt(np.square(x1 - x2) + np.square(y1 - y2))

matrix = []
for a in coords_a:
    row = []
    for b in coords_b:
        row.append(euclidean_dist(*a, *b))
    matrix.append(row)
    
matrix = np.array(matrix)

您可以想象,这个嵌套的 for 循环非常耗时,仅需要 2000 个坐标对就需要 25 秒。有没有推荐的方法来矢量化这种叉积?

提前致谢。

【问题讨论】:

  • 为什么需要惰性计算?您能否详细说明您的实际问题?你能做每列计算吗?你的数组有多大?
  • "Lazy" 指的是我下面的示例,因为它没有矢量化。我的问题是,这个计算必须在几千个集合上执行,每个集合包含 2000 到 5000 个坐标。
  • 5000x5000(X4floats) 计算应该很容易用几乎任何系统进行矢量化计算。那么,您希望矢量化的功能究竟是什么?这取决于功能。例如,对于欧几里得距离,有内置函数。
  • 我认为矢量化实现取决于您需要应用的功能。
  • 对于在 numpy 中作为 ufunc 可用的函数,我敢打赌,通过 ufunc 获取外部产品会快得多。但任何任意函数都不一定能以这种方式使用。

标签: python arrays numpy


【解决方案1】:

我想加 2 美分,因为并非每个函数都已经在 numpy 或 scipy 中实现。一般来说,您可以使用numpy broadcasting 来实现矢量化解决方案。 对于欧几里得距离的具体情况,你是怎么做的:

import numpy as np

# Define the arrays of coordinates
coords_a = np.random.random((20, 2))
coords_b = np.random.random((20, 2))

# Expand their dimensions
a = coords_a[:, None]
b = coords_b[None, None]

# Use broadcasting to compute pairwise difference
d = a-b

# Apply formula for euclidean distance
r = np.sqrt(np.sum(d**2, axis=-1)) 

在这种特定情况下scipy.spatial.distance.cdist 的时间性能要快得多,但并非所有功能都可用:

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

a = np.random.random((10_000, 2))
b = np.random.random((10_000, 2))

euc_broadcast = lambda a,b: np.sqrt(np.sum(np.square(a[:, None]-b[None, :]), axis=-1))

%timeit euc_broadcast(a, b)
3.39 s ± 149 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit cdist(a, b)
603 ms ± 13.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【讨论】:

    【解决方案2】:

    对于您的具体示例,您可以这样做:

    from scipy.spatial.distance import cdist
    cdist(coords_b,coords_a)
    

    一般来说,矢量化取决于您的功能。

    【讨论】:

      猜你喜欢
      • 2015-09-23
      • 2010-11-26
      • 2015-04-25
      • 1970-01-01
      • 2020-11-29
      • 2018-02-14
      • 1970-01-01
      相关资源
      最近更新 更多