在numpy中我想制作一个2d arrray(r,by 2 ** r),其中列都是可能的二进制列。
例如,如果列的高度为5,则列将为
[0,0,0,0,0], [0,0,0,0,1], [0,0,0,1,0], [0,0,0,1,1], [0,0,1,0,0], ...
我的解决方案是
np.array(list(itertools.product([0,1],repeat = c))).T
这看起来非常难看。有更优雅的方式吗?
答案 0 :(得分:4)
你可以在这里使用一些broadcasting
,如此 -
(((np.arange(2**r)[:,None] & 2**np.arange(r)[::-1]))>0).astype(int)
对于r
和0
之间的8
,您还可以使用np.unpackbits
-
np.unpackbits(np.arange(2**r,dtype='uint8')[:,None], axis=1)[:,8-r:]
运行时测试 -
案例#1(原件r = 5
):
In [217]: r = 5
In [218]: from itertools import product
In [219]: %timeit np.array(list(product([0,1], repeat=5)))
10000 loops, best of 3: 33.9 µs per loop
In [220]: %timeit np.unpackbits(np.arange(2**r,dtype='uint8')[:,None], axis=1)[:,8-r:]
100000 loops, best of 3: 10.6 µs per loop
In [221]: %timeit (((np.arange(2**r)[:,None] & 2**np.arange(r)[::-1]))>0).astype(int)
10000 loops, best of 3: 31.1 µs per loop
案例#2(较大r
):
In [242]: r = 15
In [243]: %timeit (((np.arange(2**r)[:,None] & 2**np.arange(r)[::-1]))>0).astype(int)
100 loops, best of 3: 6.6 ms per loop
In [244]: %timeit np.array(list(product([0,1], repeat=r)))
10 loops, best of 3: 77.5 ms per loop
答案 1 :(得分:3)
它不是那么笨拙而是相当优雅:
r = 5
boolcols = [[y&1<<x and 1 for x in range(r)[::-1]] for y in range(2**r)]
对中心部分的一些澄清可能有用:
y&1<<x and 1
这相当于
(y&(1<<x)) and 1
让我们假装x = 3而y = 5然后得到:
1<<x
为1<<3
,二进制表示法为1000
。二进制1向左移3步。在python中,您可以编写0b1000
或8
。 Read more y&(1<<x)
现在是5&8
,它是0101
和1000
的按位'与',0
(0) and 1
,产生0
注意:强> 使用timeit来衡量其与其他解决方案的性能之后,这不是您应该选择使用的那个!我在每次测试中都比较慢。例如:
In [21]: r = 15
In [23]: %timeit [[y&1<<x and 1 for x in range(r)[::-1]] for y in range(2**r)]
10 loops, best of 3: 39.8 ms per loop
In [30]: %timeit (((np.arange(2**r)[:,None] & 2**np.arange(r)[::-1]))>0).astype(int)
1000 loops, best of 3: 1.31 ms per loop
答案 2 :(得分:3)
另一个非笨拙的解决方案:
r = 3
print [map(int, list('{:0{w}b}'.format(x, w=r))) for x in xrange(2**r)]
,并提供:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
答案 3 :(得分:1)
这个怎么样?
np.array([list("0"*(r-1-int(np.log2(i)))+"{0:b}".format(i)) if i>0 else [i]*r for i in range(0,2**r)]).astype(int)
修改强>
我注意到在格式化解决方案中不必使用log2计算:
frmt = "{0:0"+str(r)+"b}"
print [map(int,list(frmt.format(i))) for i in range(0,2**r)]
和时差......
In [17]: timeit [map(int,list(frmt.format(i))) for i in range(0,2**r)]
10000 loops, best of 3: 171 µs per loop
In [18]: timeit np.array([list("0"*(r-1-int(np.log2(i)))+"{0:b}".format(i)) if i>0 else [i]*r for i in range(0,2**r)]).astype(int)
1000 loops, best of 3: 514 µs per loop
答案 4 :(得分:1)
itertools.product
是一个快速的C代码; np.array
是较慢的通用代码。在适当的情况下,np.fromiter
可以更快。但fromiter
需要平面输入,而不是嵌套列表。但另一个itertools
可以很好地平整列表。
以下是一些迭代时间比较:
In [72]: timeit list(product([0,1],repeat=5))
100000 loops, best of 3: 7.03 us per loop
In [73]: timeit list(chain(*product([0,1],repeat=5)))
100000 loops, best of 3: 18.3 us per loop
In [74]: timeit np.fromiter(chain(*product([0,1],repeat=5)),int,count=160).reshape(-1,5)
10000 loops, best of 3: 33.8 us per loop
In [75]: timeit np.array(list(product([0,1],repeat=5)))
10000 loops, best of 3: 65.1 us per loop
在这种情况下,包括count
胜利fromiter
没有太大区别。
链接发电机有一定的Pythonic优雅。
通过比较,我对纯粹numpy方法的时间有点慢:
In [85]: timeit (((np.arange(2**5)[:,None] & 2**np.arange(5)[::-1]))>0).astype(int)
10000 loops, best of 3: 38.1 us per loop
但是@Divakar表明这个解决方案可以更好地扩展。