Numpy有一个库函数np.unpackbits
,它会将uint8
解压缩到长度为8的位向量中。是否有相应快速的方法来解压缩较大的数字类型?例如。 uint16
或uint32
。我正在研究一个涉及数字之间频繁转换,数组索引和它们的位向量表示的问题,瓶颈是我们的打包和解包函数。
答案 0 :(得分:10)
您可以使用view
和unpackbits
输入:
unpackbits(arange(2, dtype=uint16).view(uint8))
输出:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
对于a = arange(int(1e6), dtype=uint16)
,这在我的机器上大约7毫秒非常快
%%timeit
unpackbits(a.view(uint8))
100 loops, best of 3: 7.03 ms per loop
至于字节顺序,您必须查看http://docs.scipy.org/doc/numpy/user/basics.byteswapping.html并根据您的需要在那里应用建议。
答案 1 :(得分:3)
这是我使用的解决方案:
def unpackbits(x,num_bits):
xshape = list(x.shape)
x = x.reshape([-1,1])
to_and = 2**np.arange(num_bits).reshape([1,num_bits])
return (x & to_and).astype(bool).astype(int).reshape(xshape + [num_bits])
这可与任何维ndarray一起使用,并且可以解压缩所需的许多位。它还不涉及任何循环。
答案 2 :(得分:2)
我也没有找到任何函数,但是使用Python的内置struct.unpack可以帮助使自定义函数比移动和更长的uint更快(注意我使用的是uint64)。
>>> import struct
>>> N = np.uint64(2 + 2**10 + 2**18 + 2**26)
>>> struct.unpack('>BBBBBBBB', N)
(2, 4, 4, 4, 0, 0, 0, 0)
想法是将它们转换为uint8,使用unpackbits,连接结果。或者,根据您的应用程序,使用structured arrays可能更方便。
还有内置的bin()函数,它产生0和1的字符串,但我不确定它有多快,也需要后处理。
答案 3 :(得分:0)
这适用于任意uint 的任意数组(即,对于多维数组以及大于uint8最大值的数字)。
它循环遍历位数,而不是数组元素的数量,因此速度相当快。
def my_ManyParallel_uint2bits(in_intAr,Nbits):
''' convert (numpyarray of uint => array of Nbits bits) for many bits in parallel'''
inSize_T= in_intAr.shape
in_intAr_flat=in_intAr.flatten()
out_NbitAr= numpy.zeros((len(in_intAr_flat),Nbits))
for iBits in xrange(Nbits):
out_NbitAr[:,iBits]= (in_intAr_flat>>iBits)&1
out_NbitAr= out_NbitAr.reshape(inSize_T+(Nbits,))
return out_NbitAr
A=numpy.arange(256,261).astype('uint16')
# array([256, 257, 258, 259, 260], dtype=uint16)
B=my_ManyParallel_uint2bits(A,16).astype('uint16')
# array([[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]], dtype=uint16)