在numpy的向量化的矩阵曼哈顿距离

Sya*_*man 4 python numpy vectorization

我正在尝试实现一个有效的矢量化numpy来制作曼哈顿距离矩阵.我熟悉用于使用点积创建高效欧几里德距离矩阵的构造,如下所示:

A = [[1, 2]   
     [2, 1]]

B = [[1, 1],
     [2, 2],
     [1, 3],
     [1, 4]]

def euclidean_distmtx(X, X):
    f = -2 * np.dot(X, Y.T)
    xsq = np.power(X, 2).sum(axis=1).reshape((-1, 1))
    ysq = np.power(Y, 2).sum(axis=1)
    return np.sqrt(xsq + f + ysq)
Run Code Online (Sandbox Code Playgroud)

我想实现类似的东西,但使用曼哈顿距离代替.到目前为止,我已经接近但是试图重新安排绝对差异.据我了解,曼哈顿的距离是

\ sum_i | x_i  -  y_i |  = | x_1  -  y_1 |  + | x_2  -  y_2 |  + ...

我试图通过考虑绝对函数是否完全不适用于解决这个问题来给我这个等价

\ sum_i x_i  -  y_i =\sum_i x_i  - \sum_i y_i

这给了我以下矢量化

def manhattan_distmtx(X, Y):
    f = np.dot(X.sum(axis=1).reshape(-1, 1), Y.sum(axis=1).reshape(-1, 1).T)
    return f / Y.sum(axis=1) - Y.sum(axis=1)
Run Code Online (Sandbox Code Playgroud)

我认为我是正确的轨道,但我不能移动值而不删除每个向量元素之间的差异的绝对函数.我确信在绝对值周围有一个聪明的伎俩,可能是通过使用np.sqrt平方值或其他东西,但我似乎无法实现它.

Div*_*kar 7

我不认为我们可以在这里利用基于BLAS的矩阵乘法,因为这里没有涉及元素乘法.但是,我们没有其他选择.

方法#1

我们可以使用具有曼哈顿距离的Scipycdist,其可选的度量参数设置为'cityblock'-

from scipy.spatial.distance import cdist

out = cdist(A, B, metric='cityblock')
Run Code Online (Sandbox Code Playgroud)

方法#2 - A.

我们也可以利用broadcasting,但内存需求更多 -

np.abs(A[:,None] - B).sum(-1)
Run Code Online (Sandbox Code Playgroud)

方法#2 - B.

这可以重写为使用更少的内存,对具有两个cols的输入数组进行切片和求和 -

np.abs(A[:,0,None] - B[:,0]) + np.abs(A[:,1,None] - B[:,1])
Run Code Online (Sandbox Code Playgroud)

方法#2 - C.

移植broadcasting版本以利用模块更快的absolute计算-numexpr

import numexpr as ne
A3D = A[:,None]
out = ne.evaluate('sum(abs(A3D-B),2)')
Run Code Online (Sandbox Code Playgroud)

  • 很全面!我相信方法 2B 需要遍历所有列。根据`timeit`,`scipy` 是最快的。方法 C 看起来很丑;) 编辑:错字 (2认同)