我正在尝试将一个 numpy 整数数组(比方说 A=[3,5,2]
)转换为一个具有最低有效位优先格式和特定长度的 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 个值用于最后一个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
表示具体的 ln(在示例中为 6)
有没有更快的方法来做到这一点?
提前致谢。
编辑: 我早该指出。 A
也可以有负值。例如,如果 A=[-11,5]
和 ln=6
,则返回的数组应该是:
A'=[-1 -1 0 -1 0 0 1 0 1 0 0 0]
请注意,ln=6
只是一个示例。甚至可能是 60。
很抱歉遗漏了这部分要求。
这是一个矢量化的 -
((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()
sample 运行-
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 版本,它只是输入的一个 View ,因此内存效率高 -
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()
我是一名优秀的程序员,十分优秀!