如何计算两个二维数组的曼哈顿距离(或 L1/cityblock)?

how to calculate Manhattan distance (or L1/ cityblock) for two 2D array?

对于一维 vector/array 它更容易。例如:

array1 = [1, 2, 3] 
array2 = [1, 1, 1]

曼哈顿距离为:(0+1+2) 即 3

import numpy as np
def cityblock_distance(A, B):
    result = np.sum([abs(a - b) for (a, b) in zip(A, B)])
    return result

2 个点的输出将是:3 但是 2D array/vector 呢?例如,两个二维向量的曼哈顿(或 L1 或城市街区)将是什么(如下):

arr1 = [[29, 30, 36, 30, 18],[37, 37, 49, 54, 23]]
arr2 = [[31, 33, 37, 34, 22],[37, 38, 50, 58, 26]]

如果我使用上面提到的代码,它会给出 3 作为 1 D 向量的输出。对于 2D 向量,输出显示为 2281。在我看来,逻辑曼哈顿距离应该是这样的:

difference of the first item between two arrays: 2,3,1,4,4 which sums to 14

difference of the second item between two array:0,1,1,4,3 which is 9.

总和为 23,因此这两个二维数组之间的曼哈顿距离为 23。

是我计算有误还是我的L1距离概念有问题?

您可以修改您的代码以通过依次比较二维数组中的每个列表(使用您的一维案例代码)然后对结果求和来计算所需的结果:

def cityblock_distance(A, B):
    result = np.sum([np.sum([abs(a - b) for (a, b) in zip(C, D)]) for C, D in zip(A, B)])
    return result
cityblock_distance(arr1,arr2)

输出:

23

如果 arr1arr2 是 numpy 数组,您可以使用:

# skip if already numpy arrays:
arr1 = np.array(arr1)
arr2 = np.array(arr2)

x = np.sum(np.abs(arr1 - arr2))
print(x)

打印:

23

您编写的代码将无法运行,即使在修复缩进后也是如此:

In [177]: 
     ...: def cityblock_distance(A, B):
     ...:     result = np.sum([abs(a - b) for (a, b) in zip(A, B)])
     ...:     return result
     ...: 

In [178]: arr1=[[29, 30, 36, 30, 18],[37, 37, 49, 54, 23]]; arr2=[[31, 3
     ...: 3, 37, 34, 22],[37, 38, 50, 58, 26]]

In [179]: cityblock_distance(arr1, arr2)
------------------------------------------------------------------------
TypeError                              Traceback (most recent call last)
<ipython-input-179-d1b44e49141d> in <module>
----> 1 cityblock_distance(arr1, arr2)

<ipython-input-177-907001cbfc9b> in cityblock_distance(A, B)
      1 def cityblock_distance(A, B):
----> 2     result = np.sum([abs(a - b) for (a, b) in zip(A, B)])
      3     return result

<ipython-input-177-907001cbfc9b> in <listcomp>(.0)
      1 def cityblock_distance(A, B):
----> 2     result = np.sum([abs(a - b) for (a, b) in zip(A, B)])
      3     return result

TypeError: unsupported operand type(s) for -: 'list' and 'list'

如果转换为数组,您将获得所需的 L1 范数:

In [180]: cityblock_distance(np.array(arr1), np.array(arr2))
Out[180]: 23

但是,因为默认情况下 numpy.sum 对数组中的所有元素求和,所以您可以完全省略列表理解:

In [181]: np.sum(abs(np.array(arr1)-np.array(arr2)))
Out[181]: 23

维基百科将您的规范称为 "entry-wise 1,1-norm". You can compute the matrix 1-norm ("maximum absolute row sum") with numpy.linalg.norm:

In [193]: np.linalg.norm(np.array(arr1)-np.array(arr2), 1)
Out[193]: 8.0

使用neulab计算:

首先,安装它:

pip install neulab

并使用它:

from neulab.Algorithms import ManhattanMetric
arr1 = [[29, 30, 36, 30, 18],[37, 37, 49, 54, 23]]
arr2 = [[31, 33, 37, 34, 22],[37, 38, 50, 58, 26]]
dist = ManhattanMetric(vector1=arr1, vector2=arr2)

输出:23.0

您还可以在 neulab 中使用其他指标。 阅读文档 https://pypi.org/project/neulab