我创建了一个小函数,它将整数length
作为输入,并返回所有numpy
整数的二进制表示的array
2**length
范围[0:2**length-1]
。
import numpy as np
def get_bitstrings(length):
# We need to binary-fy 2^length numbers.
iterations = 2**length
# Pre-allocate memory.
the_array = np.zeros((iterations, length))
# Go through all decimals in the range [0:iterations-1]
for num in range(iterations):
# Get binary representation in string format with 'length' zeroes padded
t_string = '{f_num:0{f_width}b}'.format(f_num=num, f_width=length)
# Convert to a Python list
t_list = list(t_string)
# Convert to Numpy array and store.
the_array[num,:] = np.array(t_list)
return the_array
if __name__ == '__main__':
var1 = get_bitstrings(2)
var2 = get_bitstrings(3)
print('var1:\n{}\n'.format(var1))
print('var2:\n{}\n'.format(var2))
产生:
var1:
[[ 0. 0.]
[ 0. 1.]
[ 1. 0.]
[ 1. 1.]]
var2:
[[ 0. 0. 0.]
[ 0. 0. 1.]
[ 0. 1. 0.]
[ 0. 1. 1.]
[ 1. 0. 0.]
[ 1. 0. 1.]
[ 1. 1. 0.]
[ 1. 1. 1.]]
该过程包括将每个整数的二进制表示形式作为字符串(在它之前填充0,使得长度在length
处保持不变),将字符串转换为Python列表,然后转换列表进入numpy
array
。
我发现这是满足每个位是数组中一个条目的要求的唯一方法 - 即,bitstring 1010
是1x4
numpy
array
而不仅仅是1x1
数组中的整数。但我确信有更好的选择,因此问题。
你可以想象,问题在于效率低下。我想知道我是否可以通过使用Python / Numpy技巧来改进它。
修改的: 我以前在MATLAB中用这个片段做了这个:
t_length = 5; dc = [0:2 ^ t_length-1]&#39 ;; bc = rem(floor(dc * pow2( - (t_length-1):0)),2);
但是对于Python / Numpy来说,我是一个完整的菜鸟!也许它会激励某人。 :-)
答案 0 :(得分:4)
你可以使用NumPy的广播和矢量化操作来相当有效地完成这项工作:
>>> from numpy import arange, newaxis
>>> powers_of_two = 2**arange(4)[::-1]
>>> (arange(2**4)[:, newaxis] & powers_of_two) / powers_of_two
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]])
简要说明:我们将所有整数从0到15(arange(2**4)
),然后重新整形以给出一个形状(16, 1)
的数组(这是[:, newaxis]
切片部分) 。然后我们采用按位 - 并且使用2的幂,从最高到最低(2**arange(4)[::-1]
)。重新整形确保按位和操作作为一种“外部”操作执行:我们采用原位arange
的按位和每个元素与powers_of_two
数组的每个元素。这是NumPy的broadcasting和slicing正在进行中。缺少明确的Python级for
循环应该比基于for
循环或列表推导的解决方案明显更快。
这里有点光滑,事实证明,更快,替代沿着相同的路线:
>>> from numpy import arange, newaxis
>>> arange(2**4)[:,newaxis] >> arange(4)[::-1] & 1
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]])
与往常一样,如果效率是一个问题,那么您应该充分利用Python以timeit和profile模块的形式提供的工具。使用length=16
的机器上的计时似乎表明第二个变体明显快于第一个:
taniyama:~ mdickinson$ python -m timeit -s "from numpy import arange, newaxis" "arange(1<<16)[:, newaxis] >> arange(16)[::-1] & 1"
100 loops, best of 3: 4.08 msec per loop
taniyama:~ mdickinson$ python -m timeit -s "from numpy import arange, newaxis" "(arange(1<<16)[:, newaxis] & 2**arange(16)[::-1]) / 2**arange(16)[::-1]"
10 loops, best of 3: 21.6 msec per loop
答案 1 :(得分:1)
一种方法是使用numpy.binary_repr
。它将产生一个字符串,但您可以轻松地将其转换为整数或浮点数组(只需更改dtype
参数)。例如:
import numpy as np
k = 4
print np.array([list(np.binary_repr(x, k)) for x in range(2**k)], dtype=int)
这会产生:
[[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]]
或者,如果你想要一个更易阅读的版本:
def bitstrings(k):
binary = [np.binary_repr(item, width=k) for item in range(2**k)]
return np.array([list(item) for item in binary], dtype=int)