Is there a shortcut to Convert binary (0|1) numpy array to integer or binary-string ? F.e.
b = np.array([0,0,0,0,0,1,0,1])
=> b is 5
np.packbits(b)
works but only for 8 bit values ..if the numpy is 9 or more elements it generates 2 or more 8bit values. Another option would be to return a string of 0|1 ...
What I currently do is :
ba = bitarray()
ba.pack(b.astype(np.bool).tostring())
#convert from bitarray 0|1 to integer
result = int( ba.to01(), 2 )
which is ugly !!!
This tutorial will teach you how to use the os and pathlib libraries to do just that! The Python bin () function is short for binary and allows us to convert an integer to a binary string, which is prefixed by '0b'. In later section, you’ll learn how to convert the integer using Python without the prefix.
Solution: First, let’s start off by asking ourselves what a non-integer number in binary looks like. By analogy to a decimal number, the binary number 0 .101 2 would look like: 0. 101 2 = 1 * 1/2 1 + 0 *1/2 2 + 1 * 1/2 3 .
By analogy to a decimal number, the binary number 0 .101 2 would look like: 0. 101 2 = 1 * 1/2 1 + 0 *1/2 2 + 1 * 1/2 3 . To print the decimal part, we can multiply by 2 and check if 2*n is greater than or equal to 1. This is essentially “shifting” the fractional sum. That is: If r >= 1, then we know that n had a 1 right after the decimal point.
By analogy to a decimal number, the binary number 0 .101 2 would look like: 0. 101 2 = 1 * 1/2 1 + 0 *1/2 2 + 1 * 1/2 3 .
One way would be using dot-product
with 2-powered
range array -
b.dot(2**np.arange(b.size)[::-1])
Sample run -
In [95]: b = np.array([1,0,1,0,0,0,0,0,1,0,1])
In [96]: b.dot(2**np.arange(b.size)[::-1])
Out[96]: 1285
Alternatively, we could use bitwise left-shift operator to create the range array and thus get the desired output, like so -
b.dot(1 << np.arange(b.size)[::-1])
If timings are of interest -
In [148]: b = np.random.randint(0,2,(50))
In [149]: %timeit b.dot(2**np.arange(b.size)[::-1])
100000 loops, best of 3: 13.1 µs per loop
In [150]: %timeit b.dot(1 << np.arange(b.size)[::-1])
100000 loops, best of 3: 7.92 µs per loop
Reverse process
To retrieve back the binary array, use np.binary_repr
alongwith np.fromstring
-
In [96]: b = np.array([1,0,1,0,0,0,0,0,1,0,1])
In [97]: num = b.dot(2**np.arange(b.size)[::-1]) # integer
In [98]: np.fromstring(np.binary_repr(num), dtype='S1').astype(int)
Out[98]: array([1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1])
My timeit results:
b.dot(2**np.arange(b.size)[::-1])
100000 loops, best of 3: 2.48 usec per loop
b.dot(1 << np.arange(b.size)[::-1])
100000 loops, best of 3: 2.24 usec per loop
# Precompute powers-of-2 array with a = 1 << np.arange(b.size)[::-1]
b.dot(a)
100000 loops, best of 3: 0.553 usec per loop
# using gmpy2 is slower
gmpy2.pack(list(map(int,b[::-1])), 1)
100000 loops, best of 3: 10.6 usec per loop
So if you know the size ahead of time, it's significantly faster to precompute the powers-of-2 array. But if possible, you should do all computations simultaneously using matrix multiplication like in Geoffrey Anderson's answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With