我正在尝试将一个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
也可以具有负值。例如,如果A
和A=[-11,5]
,则返回的数组应为:
ln=6
请注意,A'=[-1 -1 0 -1 0 0 1 0 1 0 0 0]
仅是示例。甚至可能是60。
很抱歉错过了这部分要求。
答案 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)