在这里使用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,但它们几乎给了我类似的东西。
答案 0 :(得分:4)
尝试这种方法,沿着axis = 1
创建一个新轴,然后使用sum
进行广播和统计真假或非零:
(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)这是一个2d数组有形状(3,6)
arr
#array([[1, 0, 0, 1, 1, 0],
# [1, 0, 0, 0, 0, 0],
# [1, 1, 1, 1, 0, 0]])
3)这会触发广播,因为它们的形状不匹配,并且2d数组 arr 首先沿着3d数组 arr [:,None,:] <的0轴广播/ em>,然后我们有一个形状(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
计算了多少元素不相等,即给出汉明距离的真实。
答案 1 :(得分:1)
由于我不理解的原因
(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
<强>更新强>
部分原因似乎是浮动速度比其他dtypes快:
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