2

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.

6
  • Are the first 4 columns always going to be full of zeros? Commented Sep 12, 2017 at 20:18
  • No, they aren't, example above is only the first 10 rows. So in some rows, they are filled with 1 or 0. The result I got above is by using Matlab command bi2de Commented Sep 12, 2017 at 20:20
  • So, you would need uint16 to store the output values, right? Commented Sep 12, 2017 at 20:34
  • Possible duplicate of Binary numpy array to list of integers? Commented Sep 12, 2017 at 20:44
  • @Divakar: It doesn't have to be in 'uint16', what I want to have is they are fit in 12 bits. Commented Sep 12, 2017 at 20:57

2 Answers 2

4

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])
Sign up to request clarification or add additional context in comments.

3 Comments

Result is still not the same as I shown in my question above, I expect to get these unsigned integer number '250, 248, 248, 250, 248, 248, 248, 248, 248, 248'.
@Javen Well I added variety there by adding two 1s in row1 and one 1 in last row for b. So, my b is different and hence that different output.
yes it works like a charm, but I need to reverse first each row to MSB-LSB. I prefer to use code In [1048], it works pretty fast. One more thing, I did some mistakes, the array above should be 11 bits not 12 bits as I put it in my question. Thanks again.
1

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.

1 Comment

thank you so much for your help. Yes, it works too but I need to reverse bit in each row so the order will be MSB-LSB. The bits I show in my question supposed to 11 bits, not 12 bits. With this 11 bits, it would produce the same result as I put in my question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.