转化的最快(或最“Pythonic”)方式是什么
x = [False, False, True, True]
进入12
? (如果有这样的方式。)
如果x
而不是numpy.array
个布尔怎么办?是否有特殊命令?
我有一个大的m-by-n布尔数组,其中每个n元素行代表一个高维特征向量的低维散列。 (在上面的例子中,n = 4.)我想知道答案,以便尽可能地压缩我的数据。谢谢。
编辑:感谢您的回复!使用以下测试代码,
t = 0
for iter in range(500):
B = scipy.signbit(scipy.randn(1000,20))
for b in B:
t0 = time.clock()
# test code here
t1 = time.clock()
t += (t1-t0)
print t
...这是我的Thinkpad笔记本电脑上的运行时间:
当然,我欢迎任何可能确认或反驳我的数据的独立测试!
编辑:在下面的回答中,将int(j)
更改为简单j
仍然有效,但运行速度慢了六倍!然后,如果使用int
投射bool,其他答案可能会更快。但我懒得再测试一切。
编辑:liori发布了独立测试的结果here。
答案 0 :(得分:10)
从各种其他答案中获取各种想法,这是另一种方法:
sum(1<<i for i, b in enumerate(x) if b)
在我的测试中速度非常快 - 即使它像疯了一样溢出,也可以使用numpy方法获取大量的数据。我使用liori的测试模块进行测试。史蒂夫的方法,我建议的改变,只是快几点。但是,如果需要一次完成很多这类转换(并且没有太多位),我认为numpy会更快。
答案 1 :(得分:6)
大多数Pythonic可能就是这样:
sum(2**i*b for i, b in enumerate(x))
很难判断它是否也是最快的。
在numpy我会用
numpy.sum(2**numpy.arange(len(x))*x)
但对于小型数组x
来说这不会更快,并且它不适用于大型数组x
,因为使用机器大小整数而不是Pythons任意精度整数。
答案 2 :(得分:3)
reduce(lambda a,b:2*a+b, reversed(x))
如果你在数组末尾有最低位,你可以摆脱revers()。这也适用于numpy.array,并且不需要enumerate()。从我的测试来看似乎也更快:不需要使用取幂。
答案 3 :(得分:2)
这是一种优雅,pythonic,始终如一的方式:
def powers(x):
"""yield powers of x, starting from x**0 forever"""
power = 1
while True:
yield power
power *= x
def bools_to_int(bools):
# in Python 2, use itertools.izip!
return sum(int(place) * place_weight for place_weight, place in
zip(powers(2), bools))
请注意,你可以摆脱powers
(通过枚举和平方理解,就像其他答案一样) - 但也许这样更清楚。
答案 4 :(得分:2)
我最初的尝试,仅供参考:
def bool2int(x):
y = 0
for i,j in enumerate(x):
if j: y += int(j)<<i
return y
答案 5 :(得分:1)
这样的东西?
>>> x = [False, False, True, True]
>>> sum([int(y[1])*2**y[0] for y in enumerate(x)])
12
您可以使用list()
强制转换将numpy数组转换为常规列表。
>>> a = numpy.array([1,2,3,4])
>>> a
array([1, 2, 3, 4])
>>> list(a)
[1, 2, 3, 4]
答案 6 :(得分:1)
如果您有矩阵,您可能希望这样做:
#precompute powers of two
vals = 2.**np.arange(20)
B = ....
compressed = np.dot(B, vals) # matrix multiplication.
np.dot应该比Python中的任何循环都快。快得多。
答案 7 :(得分:1)
我正在尝试ipython %timeit
,似乎执行以下操作更快:
y = 0
for i,j in enumerate(x):
if j: y += 1<<i
此外,如果您的布尔向量是numpy.ndarray,将其转换为python数组x.tolist()
并运行相同的工具似乎在这种情况下更快。这一切都是微不足道的,但是在这些速度下,边际加起来也很好。
答案 8 :(得分:1)
numpy具有packbits功能。 它还支持沿轴的操作:
In [3]: B = scipy.signbit(scipy.randn(1000,8)).astype("i1")
In [3]: B[0]
Out[3]: array([0, 1, 0, 0, 0, 1, 0, 0], dtype=int8)
In [4]: np.packbits(B[0])
Out[4]: array([68], dtype=uint8)
In [5]: %timeit np.packbits(B, axis=1)
10000 loops, best of 3: 37 µs per loop
适用于较大尺寸的int8尺寸,您必须移动和/或
In [8]: x # multiple of 8
Out[8]: array([1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], dtype=int8)
In [9]: r = np.packbits(x).astype(np.int32); r
Out[9]: array([171, 129], dtype=uint8)
In [10]: r[0] << 8 | r[1]
Out[10]: 33237
In [11]: sum(1<<i for i, b in enumerate(x[::-1]) if b)
Out[11]: 33237
如果x
不是8的倍数,则必须用零填充
答案 9 :(得分:0)
如果您愿意为混音添加另一个扩展名,我将pack()和unpack()添加到gmpy的开发分支中。我的测试显示它可能快2倍或3倍。
>>> import gmpy2
>>> gmpy2.pack([0,0,1,1],1)
mpz(12)
>>> gmpy2.unpack(12,1)
[mpz(0), mpz(0), mpz(1), mpz(1)]
免责声明:开发版本称为gmpy2,可以与稳定版本共存。它仍处于alpha阶段,但有望在几周内成为beta版。您需要安装GMP和MPFR库。来源位于http://code.google.com/p/gmpy/source/checkout