I have a long 2D matrix of Numpy array object whose dimension is n x 12. Here is the first 10 rows of this matrix:
b = ([[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0]], dtype=uint8)
What I want to do with this array is to convert it to unsigned integer. As far as I know the fastest way to do it is by using np.packbits function. However this function only packs 8 bits into integer while my array above has 12 bits in each row. What I expect when converting array above to unsigned integer are:
250, 248, 248, 250, 248, 248, 248, 248, 248, 248
Does any one know how get above result ? I also tried by np.packbits above by extending the bits to 16 (`.view('u2'), the result is still not as I expected. Any feedback would be appreciated. Thanks.
2 Answers 2
We could slice out the first 4 columns and last 8 columns and use np.packbits separately on those. Then, scale the first slice to account for them being the most-significant block among them and add with the second slice.
Hence, the implementation would be -
slice0 = np.packbits(b[:,:-8], axis=-1).astype(np.uint16) * 16
slice1 = np.packbits(b[:,-8:], axis=-1).astype(np.uint16)
out = slice0 + slice1
Alternatively, using sum-redcution with matrix-multiplication -
b.dot(2**np.arange(b.shape[1]-1,-1,-1))
Sample run -
In [1045]: b
Out[1045]:
array([[0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0]], dtype=uint8)
In [1046]: slice0 = np.packbits(b[:,:-8], axis=-1).astype(np.uint16) * 16
...: slice1 = np.packbits(b[:,-8:], axis=-1).astype(np.uint16)
...: out = slice0 + slice1
...:
In [1047]: out.ravel()
Out[1047]: array([1786, 248, 248, 250, 248, 248, 248, 248, 1272, 760])
In [1048]: b.dot(2**np.arange(b.shape[1]-1,-1,-1))
Out[1048]: array([1786, 248, 248, 250, 248, 248, 248, 248, 1272, 760])
3 Comments
b. So, my b is different and hence that different output.A generic solution to the problem would be
from numpy import *
b = ([[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0]])
def bin2int(x):
y = 0
for i,j in enumerate(x):
y += j<<i
return y
result = [bin2int(x[::-1]) for x in b]
so you don't have to worry about how many bits anymore.
uint16to store the output values, right?