I want to efficiently convert values from a list (or numpy array) into a numpy array of bits: A negative value should become a 0 in the new array, and a positive value a 1 in the new array.
E.g.,
>> import numpy as np
>> np.clip([1,2,3,-1,-2], a_min=0, a_max=1)
array([1, 1, 1, 0, 0])
However, if I have floats in the list, this method keeps them as is:
>> np.clip([1,0.45,3,-1,-2], a_min=0, a_max=1)
array([ 1. , 0.45, 1. , 0. , 0. ])
Is there a good way of circumventing this behavior? One way would be to round the values. But I would want everything that is positive assigned a 1. If I would use np.around()
, this would round 0.45 -> 0.
To map everything greater than 0 to 1 (and everything less to 0) you could use np. where:
In [25]: np.where(np.array([1,0.45,3,-1,-2]) > 0, 1, 0)
Out[25]: array([1, 1, 1, 0, 0])
or
In [29]: (np.array([1,0.45,3,-1,-2]) > 0).astype('i1')
Out[29]: array([1, 1, 1, 0, 0], dtype=int8)
Note that np.where
is returning an array with dtype int32
(4-byte ints), while astype('i1')
is returning an array with dtype int8
(1-byte ints).
If you wish to pack these binary values into a uint8, you could use np.packbits:
In [48]: x = np.array([1,0.45,3,-1,-2])
In [49]: np.packbits((x > 0).astype('i1'))
Out[49]: array([224], dtype=uint8)
In [50]: bin(224)
Out[50]: '0b11100000'
Or, as a string:
In [60]: np.packbits((x > 0).astype('i1')).tostring()
Out[60]: '\xe0'
In [62]: bin(0xe0)
Out[62]: '0b11100000'