I have integers in the range 0..2**m - 1
and I would like to convert them to binary numpy arrays of length m
. For example, say m = 4
. Now 15 = 1111
in binary and so the output should be (1,1,1,1)
. 2 = 10
in binary and so the output should be (0,0,1,0
). If m
were 3
then 2
should be converted to (0,1,0)
.
I tried np.unpackbits(np.uint8(num))
but that doesn't give an array of the right length. For example,
np.unpackbits(np.uint8(15))
Out[5]: array([0, 0, 0, 0, 1, 1, 1, 1], dtype=uint8)
I would like a method that worked for whatever m
I have in the code.
To convert integer to binary, start with the integer in question and divide it by 2 keeping notice of the quotient and the remainder. Continue dividing the quotient by 2 until you get a quotient of zero. Then just write out the remainders in the reverse order. Here is an example of such conversion using the integer 12.
5 in binary is 101. To find decimal to binary equivalent, divide 5 successively by 2 until the quotient becomes 0. The binary equivalent can be obtained by writing the remainder in each division step from the bottom to the top.
format(num, name) function with name as "0nb" to convert an integer num to a binary string with leading zeros up to length n.
In Python, you can simply use the bin() function to convert from a decimal value to its corresponding binary value. And similarly, the int() function to convert a binary to its decimal value. The int() function takes as second argument the base of the number to be converted, which is 2 in case of binary numbers.
You should be able to vectorize this, something like
>>> d = np.array([1,2,3,4,5])
>>> m = 8
>>> (((d[:,None] & (1 << np.arange(m)))) > 0).astype(int)
array([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[1, 0, 1, 0, 0, 0, 0, 0]])
which just gets the appropriate bit weights and then takes the bitwise and:
>>> (1 << np.arange(m))
array([ 1, 2, 4, 8, 16, 32, 64, 128])
>>> d[:,None] & (1 << np.arange(m))
array([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 2, 0, 0, 0, 0, 0, 0],
[1, 2, 0, 0, 0, 0, 0, 0],
[0, 0, 4, 0, 0, 0, 0, 0],
[1, 0, 4, 0, 0, 0, 0, 0]])
There are lots of ways to convert this to 1s wherever it's non-zero (> 0)*1
, .astype(bool).astype(int)
, etc. I chose one basically at random.
One-line version, taking advantage of the fast path in numpy.binary_repr
:
def bin_array(num, m):
"""Convert a positive integer num into an m-bit bit vector"""
return np.array(list(np.binary_repr(num).zfill(m))).astype(np.int8)
Example:
In [1]: bin_array(15, 6)
Out[1]: array([0, 0, 1, 1, 1, 1], dtype=int8)
Vectorized version for expanding an entire numpy array of ints at once:
def vec_bin_array(arr, m):
"""
Arguments:
arr: Numpy array of positive integers
m: Number of bits of each integer to retain
Returns a copy of arr with every element replaced with a bit vector.
Bits encoded as int8's.
"""
to_str_func = np.vectorize(lambda x: np.binary_repr(x).zfill(m))
strs = to_str_func(arr)
ret = np.zeros(list(arr.shape) + [m], dtype=np.int8)
for bit_ix in range(0, m):
fetch_bit_func = np.vectorize(lambda x: x[bit_ix] == '1')
ret[...,bit_ix] = fetch_bit_func(strs).astype("int8")
return ret
Example:
In [1]: vec_bin_array(np.array([[100, 42], [2, 5]]), 8)
Out[1]: array([[[0, 1, 1, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 0]],
[[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 0, 1]]], dtype=int8)
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