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

时间:2017-12-10 06:38:21

标签: 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)

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

\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)

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

1 个答案:

答案 0 :(得分:5)

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

方法#1

我们可以使用具有曼哈顿距离的Scipy's cdist,其可选的指标参数设置为'cityblock' -

from scipy.spatial.distance import cdist

out = cdist(A, B, metric='cityblock')

方法#2 - A

我们还可以利用broadcasting,但需要更多内存 -

np.abs(A[:,None] - B).sum(-1)

方法#2 - B

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

np.abs(A[:,0,None] - B[:,0]) + np.abs(A[:,1,None] - B[:,1])

方法#2 - C

移植broadcasting版本以使用numexpr module更快的absolute计算 -

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