计算numpy行-行叉积的欧几里得距离?

时间:2020-08-07 11:56:20

标签: python arrays numpy

我有两个numpy数组,坐标数为n(每行两个项)。

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秒以上。有没有推荐的向量这种交叉乘积的方法?

谢谢。

2 个答案:

答案 0 :(得分:3)

我想加上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)

答案 1 :(得分:2)

对于您的特定示例,您可以执行以下操作:

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

通常,向量化取决于您的功能。