在python中对很多二进制数组进行异或的最快方法是什么?

Ala*_*ane 6 python arrays hamming-distance

我的任务是计算两组中1D二进制数组之间的汉明距离 - 一组3000个数组和一组10000个数组,每个数组长100个项目(位).这就是在100位长的物体上进行3000x10000高清计算.所有这些都必须在最多十几分钟内完成

这是我提出的最好的

#X - 3000 by 100 bool np.array 
#Y - 10000 by 100 bool np.array
hd = []
i=1
for x in X:
    print("object nr " + str(i) + "/" + str(len(X)))
    arr = np.array([x] * len(Y)) 
    C = Y^arr # just xor this array by all the arrays in the other group simultainously
    hd.append([sum(c) for c in C]) #add up all the bits to get the hamming distance
    i+=1

return np.array(hd)
Run Code Online (Sandbox Code Playgroud)

它还需要1-1.5小时才能完成.我该如何更快地完成这项工作?

Sha*_*ger 5

您应该能够通过使用numpy它来执行求和速度,而不是使用列表推导和内置sum函数(不利用numpy矢量化运算)来显着提高求和速度。

只需替换:

hd.append([sum(c) for c in C])
Run Code Online (Sandbox Code Playgroud)

与:

# Explicitly use uint16 to reduce memory cost; if array sizes might increase
# you can use uint32 to leave some wiggle room
hd.append(C.sum(1, dtype=np.uint16))
Run Code Online (Sandbox Code Playgroud)

对于2D数组,它将返回一个新的1D数组,其中每个值都是相应行的总和(由于指定了对它的操作axis 1)。例如:

>>> arr = np.array([[True,False,True], [False,False,True], [True, True,True]], dtype=np.bool)
>>> arr.sum(1, np.uint16)
array([ 2, 1, 3], dtype=uint16)
Run Code Online (Sandbox Code Playgroud)

由于它可以在一次操作中完成C层的所有工作而无需进行类型转换(而不是您的原始方法需要对每一行进行操作的Python级别循环,因此隐式循环在C层时仍必须隐式进行)将每个numpy值一个一个地转换np.bool到python级别int以求和),对于您描述的数组比例,这应该运行得更快。

旁注:虽然不是性能问题的根源,但没有理由手动维护索引值;enumerate可以更快更轻松地做到这一点。只需更换:

i=1
for x in X:
    ... rest of loop ...
    i+=1
Run Code Online (Sandbox Code Playgroud)

与:

for i, x in enumerate(X, 1):
    ... rest of loop ...
Run Code Online (Sandbox Code Playgroud)

而且您会得到相同的行为,但总体上会更快,更简洁,更干净。

  • 从性能角度来看,在一个100行,每行10000个元素的输入数组上,[[C中的c的sum(c)]]在我的机器上运行大约需要2秒钟;C.sum(1,dtype = np.uint16)花费了737 µs,约占原始运行时间的0.037%(因此,仅凭此更改,可以合理地预计1-1.5小时将降至1-2秒范围) 。对于10000行(每行100个元素)而言,时间更长,但仍然相似。listcomp + sum解决方案花费了2.11秒,numpy解决方案花费了914 µs。无论哪种方式,它都应大大减少运行时间。 (2认同)