繁体   English   中英

Python-如何生成成对汉明距离矩阵

[英]Python - How to generate the Pairwise Hamming Distance Matrix

Python的初学者。 所以我在尝试仅使用numpy库来计算输入矩阵的行之间的二进制成对汉明顿距离矩阵时遇到了麻烦。 我应该避免循环并使用向量化。 例如,如果我有类似的东西:

   [ 1,  0,  0,  1,  1,  0]
   [ 1,  0,  0,  0,  0,  0]
   [ 1,  1,  1,  1,  0,  0]

矩阵应类似于:

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

也就是说,如果原始矩阵是A,汉明距离矩阵是B。B [0,1] =汉明距离(A [0]和A [1])。 在这种情况下,答案是2,因为它们只有两个不同的元素。

所以对于我的代码来说就是这样

def compute_HammingDistance(X):

     hammingDistanceMatrix = np.zeros(shape = (len(X), len(X)))
     hammingDistanceMatrix = np.count_nonzero ((X[:,:,None] != X[:,:,None].T))
     return hammingDistanceMatrix

但是,它似乎只是返回标量值而不是预期的矩阵。 我知道阵列/向量广播可能做错了,但我不知道如何解决。 我尝试使用np.sum而不是np.count_nonzero,但它们几乎都给了我类似的东西。

尝试这种方法,沿着axis = 1创建一个新轴,然后进行广播并用sum计数true或非零:

(arr[:, None, :] != arr).sum(2)

# array([[0, 2, 3],
#        [2, 0, 3],
#        [3, 3, 0]])

def compute_HammingDistance(X):
    return (X[:, None, :] != X).sum(2)

说明

1)创建一个形状为(3,1,6)的3d数组

arr[:, None, :]
#array([[[1, 0, 0, 1, 1, 0]],
#       [[1, 0, 0, 0, 0, 0]],
#       [[1, 1, 1, 1, 0, 0]]])

2)这是一个二维数组,形状为(3,6)

arr   
#array([[1, 0, 0, 1, 1, 0],
#       [1, 0, 0, 0, 0, 0],
#       [1, 1, 1, 1, 0, 0]])

3)这会触发广播,因为它们的形状不匹配,并且首先沿3d数组arr [:, None,:]的0轴广播2d数组arr ,然后我们得到形状为(1,6)的数组针对(3,6)广播。 这两个广播步骤一起对原始数组进行笛卡尔比较。

arr[:, None, :] != arr 
#array([[[False, False, False, False, False, False],
#        [False, False, False,  True,  True, False],
#        [False,  True,  True, False,  True, False]],
#       [[False, False, False,  True,  True, False],
#        [False, False, False, False, False, False],
#        [False,  True,  True,  True, False, False]],
#       [[False,  True,  True, False,  True, False],
#        [False,  True,  True,  True, False, False],
#        [False, False, False, False, False, False]]], dtype=bool)

4)沿第三轴的sum计算出不相等的元素数,即为真,得出汉明距离。

由于某些原因,我不明白这一点

(2 * np.inner(a-0.5, 0.5-a) + a.shape[1] / 2)

对于较大的数组,它似乎比@Psidom的要快得多:

a = np.random.randint(0,2,(100,1000))
timeit(lambda: (a[:, None, :] != a).sum(2), number=100)
# 2.297890231013298
timeit(lambda: (2 * np.inner(a-0.5, 0.5-a) + a.shape[1] / 2), number=100)
# 0.10616962902713567

对于非常小的示例,Psidom的速度更快:

a
# array([[1, 0, 0, 1, 1, 0],
#        [1, 0, 0, 0, 0, 0],
#        [1, 1, 1, 1, 0, 0]])

timeit(lambda: (a[:, None, :] != a).sum(2), number=100)
# 0.0004370050155557692
timeit(lambda: (2 * np.inner(a-0.5, 0.5-a) + a.shape[1] / 2), number=100)
# 0.00068191799800843

更新资料

部分原因似乎是浮点数比其他dtype更快:

timeit(lambda: (0.5 * np.inner(2*a-1, 1-2*a) + a.shape[1] / 2), number=100)
# 0.7315902590053156
timeit(lambda: (0.5 * np.inner(2.0*a-1, 1-2.0*a) + a.shape[1] / 2), number=100)
# 0.12021801102673635

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM