Blue Moon
Blue Moon

Reputation: 449

How to unpack a uint32 array with np.unpackbits

I used a piece of code to create a 2D binary valued array to cover all possible scenarios of an event. For the first round, I tested it with 2 members.

Here is my code:

number_of_members = 2
n = number_of_members
values = np.arange(2**n, dtype=np.uint8).reshape(-1, 1)
print('$$$ ===> ', values)
bin_array = np.unpackbits(values, axis=1)[:, -n:]
print('*** ===> ', bin_array)

And the result is this:

$$$ ===>  [[0]
           [1]
           [2]
           [3]]
*** ===>  [[0 0]
           [0 1]
           [1 0]
           [1 1]]

As you can see, it correctly provided my 2D binary array.

The problem begins when I intended to use number_of_members = 20. If I assign 20 to number_of_members python shows this as result:

$$$ ===>  [[  0]
           [  1]
           [  2]
           ...
           [253]
           [254]
           [255]]
*** ===>  [[0 0 0 ... 0 0 0]
           [0 0 0 ... 0 0 1]
           [0 0 0 ... 0 1 0]
           ...
           [1 1 1 ... 1 0 1]
           [1 1 1 ... 1 1 0]
           [1 1 1 ... 1 1 1]]

The result has 8 columns, but I expected an array of 32 columns. How can I unpack a uint32 array?

Upvotes: 1

Views: 1459

Answers (1)

Mad Physicist
Mad Physicist

Reputation: 114440

As you noted correctly, np.unpackbits operates only on uint8 arrays. The nice thing is that you can view any type as uint8. You can create a uint32 view into your data like this:

view = values.view(np.uint8)

On my machine, this is little-endian, which makes trimming easier. You can force little-endian order conditionally across all systems:

if values.dtype.byteorder == '>' or (values.dtype.byteorder == '=' and sys.byteorder == 'big'):
    view = view[:, ::-1]

Now you can unpack the bits. In fact, unpackbits has a nice feature that I personally added, the count parameter. It allows you to make your output be exactly 20 bits long instead of the full 32, without subsetting. Since the output will be mixed big-endian bits and little-endian bytes, I recommend displaying the bits in little-endian order too, and flipping the entire result:

bin_array = np.unpackbits(view, axis=1, count=20, bitorder='little')[:, ::-1]

The result is a (1<<20, 20) array with the exact values you want.

Upvotes: 3

Related Questions