如何创建一个二维二进制计数的Numpy数组?
创建一个像这样的数组:
[[0,0,0,0]
[0,0,0,1]
[0,0,1,0]
[0,0,1,1]
[0,1,0,0]
.
.
.
[1,1,1,1]]
我试过用binary_repr()来生成二进制数字的字符串,然后把它变成数组,但它不能把整个数组都转换成二进制表示。
4 个回答
0
如果我理解得没错,你可以使用 itertools.product
这个工具:
from itertools import product
arr = np.fromiter(product([0, 1], repeat=4), dtype=(int, 4))
print(arr)
输出结果是:
[[0 0 0 0]
[0 0 0 1]
[0 0 1 0]
[0 0 1 1]
[0 1 0 0]
[0 1 0 1]
[0 1 1 0]
[0 1 1 1]
[1 0 0 0]
[1 0 0 1]
[1 0 1 0]
[1 0 1 1]
[1 1 0 0]
[1 1 0 1]
[1 1 1 0]
[1 1 1 1]]
1
这里有两种快速的方法,可以从已有的i位数组构建出i+1位的数组。
这是对20位的基准测试(其他解决方案稍作调整,以确保我们都在做同样的事情):
40 ms binary_counting_1
16 ms binary_counting_2
1202 ms Andrej_Kesely
4668 ms Arne
79 ms mozway
代码:
def binary_counting_1(n, dtype):
a = np.array([[]], dtype=dtype)
for i in range(n):
a = np.vstack(
[np.c_[np.zeros(2**i, dtype), a],
np.c_[np.ones(2**i, dtype), a]]
)
return a
def binary_counting_2(n, dtype):
a = np.zeros((2**n, n), dtype)
for i in range(n):
m = 2**i
a[m:2*m, -i:] = a[:m, -i:]
a[m:2*m, ~i] = 1
return a
def Andrej_Kesely(n, dtype):
return np.fromiter(product([0, 1], repeat=n), dtype=(dtype, n))
def Arne(N_DIGITS, dtype):
return np.array([list(format(i, 'b').zfill(N_DIGITS))
for i in range(2 ** N_DIGITS)], dtype=dtype)
def mozway(n, dtype):
n = 2**n
a = np.arange(n)[:,None]
M = (n-1).bit_length()
N = -(M // -8)
return np.hstack([np.unpackbits((a>>(8*x)).astype(dtype), axis=1)
for x in range(N-1, -1, -1)])[:, -M:]
funcs = binary_counting_1, binary_counting_2, Andrej_Kesely, Arne, mozway
import numpy as np
from time import time
from itertools import product
n, dtype = 20, 'uint8'
expect = funcs[0](n, dtype)
for _ in range(3):
for f in funcs:
t0 = time()
result = f(n, dtype)
print(f'{(time()-t0)*1e3 :4.0f} ms ', f.__name__)
assert (result == expect).all()
del result
2
对于不超过255的数字,可以使用 numpy.unpackbits
:
np.unpackbits(np.arange(16, dtype=np.uint8)[:,None], axis=1)[:, -4:]
[:, -4:]
是用来保留最后4位(总共8位中的一部分)。
输出结果:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 1, 1, 1]], dtype=uint8)
对于不超过65535的数字,你可以用相同的方法,把数字分成两部分(前8位和后8位):
这里有一些选定的数字示例(不是完整的范围):
a = np.array([0,1,2,254,255,256,257,512,1024])[:,None]
out = np.c_[np.unpackbits((a>>8).astype(np.uint8), axis=1),
np.unpackbits((a&255).astype(np.uint8), axis=1)]
输出结果:
array([[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
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], # 2
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0], # 254
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], # 255
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], # 256
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], # 257
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 512
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 1024
], dtype=uint8)
然后你可以继续这个过程,处理更大的数字:
a = np.array([0,1,2,254,255,256,257,512,1024,65535,65536,65537])[:,None]
np.c_[np.unpackbits((a>>16).astype(np.uint8), axis=1),
np.unpackbits((a>>8).astype(np.uint8), axis=1),
np.unpackbits(a.astype(np.uint8), axis=1),
]
array([[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],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 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],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=uint8)
这是一个通用的方法,可以生成从1到n-1的所有数字:
def numpy_packbits(n):
a = np.arange(n)[:,None]
#N = int(np.ceil(np.log2(n)/8))
#M = int(np.ceil(np.log2(n)))
M = (n-1).bit_length()
N = -(M // -8)
return np.hstack([np.unpackbits((a>>(8*x)).astype(np.uint8), axis=1)
for x in range(N-1, -1, -1)])[:, -M:]