如何将整数数组转换为特定长度的二进制数组

时间:2019-04-11 13:32:10

标签: python numpy

我正在尝试将一个A=[3,5,2]的numpy整数数组转换为具有最低有效位优先格式和特定​​长度的numpy二进制数组。也就是说,长度6的结果应如下:

A' = [1 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0]

前6个值用于A的第一个元素,后6个值用于A的第二个元素,后6个值用于{{1}的最后一个元素}。

我当前的解决方法如下:

A

其中np.multiply( np.delete( np.unpackbits( np.abs(A.astype(int)).view("uint8")).reshape(-1,8)[:,::-1].reshape(-1,64), np.s_[ln::],1).astype("float64").ravel(), np.repeat(np.sign(A), ln)) 代表特定的ln(在示例中为6)

有什么更快的方法吗?

谢谢。

编辑:我之前应该指出。 ln也可以具有负值。例如,如果AA=[-11,5],则返回的数组应为:

ln=6

请注意,A'=[-1 -1 0 -1 0 0 1 0 1 0 0 0] 仅是示例。甚至可能是60。

很抱歉错过了这部分要求。

3 个答案:

答案 0 :(得分:2)

您可以使用binary_repr

arr = np.array([3,5,2])
res = np.array([int(c) for i in arr for c in np.binary_repr(i, width=6)[::-1]])

>>>[1 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0]

[::-1]是一种以相反顺序遍历字符串的技巧:迭代步骤设置为-1。有关更多详细信息,请参见extended slices docs

或使用格式字符串(虽然看起来像是代码高尔夫球):

res = np.array([int(c) for i in arr for c in f'{i:06b}'[::-1]])

f'{i:06b}'是一个字符串,它以6位数字和前导零表示二进制i

从速度上看,这非常慢...对不起,我没有这个问题!

答案 1 :(得分:2)

这是矢量化的-

((A[:,None] & (1 << np.arange(ln)))!=0).ravel().view('i1')

另一个与np.unpackbits-

np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1].ravel()

样品运行-

In [197]: A
Out[197]: array([3, 5, 2])

In [198]: ln = 6

In [199]: ((A[:,None] & (1 << np.arange(ln)))!=0).ravel().view('i1')
Out[199]: array([1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0], dtype=int8)

In [200]: np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1].ravel()
Out[200]: array([1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0], dtype=uint8)

大型阵列上的计时-

In [201]: A = np.random.randint(0,6,1000000)

In [202]: ln = 6

In [203]: %timeit ((A[:,None] & (1 << np.arange(ln)))!=0).ravel().view('i1')
10 loops, best of 3: 32.1 ms per loop

In [204]: %timeit np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1].ravel()
100 loops, best of 3: 8.14 ms per loop

如果您可以接受2D数组输出,且每一行都保留输入中每个元素的二进制信息,那就更好了-

In [205]: %timeit np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1]
1000 loops, best of 3: 1.04 ms per loop

其他发布的方法-

# @aburak's soln
In [206]: %timeit np.multiply( np.delete( np.unpackbits( np.abs(A.astype(int)).view("uint8")).reshape(-1,8)[:,::-1].reshape(-1,64), np.s_[ln::],1).astype("float64").ravel(), np.repeat(np.sign(A), ln))
10 loops, best of 3: 180 ms per loop

# @Jacques Gaudin's soln
In [208]: %timeit np.array([int(c) for i in A for c in np.binary_repr(i, width=6)[::-1]])
1 loop, best of 3: 3.34 s per loop

# @Paul Panzer's soln
In [209]: %timeit np.unpackbits(A[:, None].view(np.uint8)[..., ::-1] if sys.byteorder=='little' else A[:, None].view(np.uint8), axis=-1)[..., :-ln-1:-1].reshape(-1)
10 loops, best of 3: 35.4 ms per loop

支持本文中第二种方法的最好的事情是,我们有一个uint8 dtype版本的输入,它只是对输入的视图,因此具有存储效率-

In [238]: A
Out[238]: array([3, 5, 2])

In [239]: A.view(np.uint8)[::8]
Out[239]: array([3, 5, 2], dtype=uint8)

In [240]: np.shares_memory(A,A.view(np.uint8)[::8])
Out[240]: True

因此,当我们使用np.unpackbits时,我们将提供与原始元素相同数量的元素。

此外,A.view(np.uint8)[::8]似乎是将int dtype数组视为uint8数组的好技巧!


要解决一般情况,我们可以扩展前面列出的方法。

方法1(对于ln最高为63):

(((np.abs(A)[:,None] & (1 << np.arange(ln)))!=0)*np.sign(A)[:,None]).ravel()

方法2:

a = np.abs(A)
m = ((ln-1)//8)+1
b = a.view(np.uint8).reshape(-1,8)[:,:m]
U = np.unpackbits(b,axis=1)
out = U.reshape(-1,m,8)[...,::-1].reshape(len(A),-1)[...,:ln]
out = (out*np.sign(A)[:,None]).ravel()

答案 2 :(得分:1)

也许我对您的解决方案的全部功能一无所知,但它似乎具有一些非必要的成分。

这是精简版本。它会检查字节序,并且在典型平台上最多可支持64位。

A = np.arange(-2, 3)*((2**40)-1)
ln = 60

np.unpackbits(np.abs(A[..., None]).view(np.uint8)[..., ::-1] if sys.byteorder=='little' else np.abs(A[..., None]).view(np.uint8), axis=-1)[..., :-ln-1:-1].view(np.int8) * np.sign(A[:, None]).astype(np.int8)

输出

array([[ 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0]], dtype=int8)