【问题标题】:Compute distance matrix with numpy用 numpy 计算距离矩阵
【发布时间】:2017-12-20 00:20:56
【问题描述】:

我正在尝试使用 numpy.更清楚地说,我有一个表示二维网格中位置的矩阵:

array([[[0, 0],
    [1, 0],
    [2, 0],
    [3, 0]],

   [[0, 1],
    [1, 1],
    [2, 1],
    [3, 1]],

   [[0, 2],
    [1, 2],
    [2, 2],
    [3, 2]],

   [[0, 3],
    [1, 3],
    [2, 3],
    [3, 3]],

   [[0, 4],
    [1, 4],
    [2, 4],
    [3, 4]]])

我可以遍历位置并计算目标位置与位置矩阵的每个位置之间的差异范数,如下所示:

pos_goal = np.array([1,2])
dist_matrix = np.zeros(l_arr.shape[:2])
for i, line in enumerate(l_arr):
    for j, pos in enumerate(line):
        dist_matrix[i,j] = np.linalg.norm(pos - pos_goal) 

dist_matrix

结果:

array([[ 2.23606798,  2.        ,  2.23606798,  2.82842712],
   [ 1.41421356,  1.        ,  1.41421356,  2.23606798],
   [ 1.        ,  0.        ,  1.        ,  2.        ],
   [ 1.41421356,  1.        ,  1.41421356,  2.23606798],
   [ 2.23606798,  2.        ,  2.23606798,  2.82842712]])

难道没有更好的方法(没有 2 个循环)吗?

【问题讨论】:

  • 距离计算是矢量运算,所以我认为,AFAIK,没有矩阵运算可以计算距离。

标签: python arrays numpy matrix


【解决方案1】:

使用scipy.spatial.distance.cdist。它需要 2D 输入,因此您可以执行以下操作:

from scipy.spatial import distance
dist_matrix = distance.cdist(l_arr.reshape(-1, 2), [pos_goal]).reshape(l_arr.shape[:2])

这非常简洁,并且对于大型数组将比基于循环或广播的手动方法更快。

【讨论】:

    【解决方案2】:

    np.linalg.norm 函数接受 axis 参数,所以你想要:

    In [6]: np.linalg.norm(l_arr - pos_goal, axis=2)
    Out[6]:
    array([[ 2.23606798,  2.        ,  2.23606798,  2.82842712],
           [ 1.41421356,  1.        ,  1.41421356,  2.23606798],
           [ 1.        ,  0.        ,  1.        ,  2.        ],
           [ 1.41421356,  1.        ,  1.41421356,  2.23606798],
           [ 2.23606798,  2.        ,  2.23606798,  2.82842712]])
    

    您可以将-1 用于“最后一个”轴:

    In [7]: np.linalg.norm(l_arr - pos_goal, axis=-1)
    Out[7]:
    array([[ 2.23606798,  2.        ,  2.23606798,  2.82842712],
           [ 1.41421356,  1.        ,  1.41421356,  2.23606798],
           [ 1.        ,  0.        ,  1.        ,  2.        ],
           [ 1.41421356,  1.        ,  1.41421356,  2.23606798],
           [ 2.23606798,  2.        ,  2.23606798,  2.82842712]])
    

    注意,我使用数组广播来获取差异:

    In [11]: l_arr - pos_goal
    Out[11]:
    array([[[-1, -2],
            [ 0, -2],
            [ 1, -2],
            [ 2, -2]],
    
           [[-1, -1],
            [ 0, -1],
            [ 1, -1],
            [ 2, -1]],
    
           [[-1,  0],
            [ 0,  0],
            [ 1,  0],
            [ 2,  0]],
    
           [[-1,  1],
            [ 0,  1],
            [ 1,  1],
            [ 2,  1]],
    
           [[-1,  2],
            [ 0,  2],
            [ 1,  2],
            [ 2,  2]]])
    

    一般来说,learning how to use broadcasting 与内置的numpy/scipy 矢量化函数相结合是实现显着速度提升的方法。

    【讨论】: