長いビット文字列に対して多くのビット単位の操作を実行する Python ライブラリに取り組んでおり、その速度を最大化するビット文字列型を見つけたいと考えています。組み込みの Python int 型である numpy、bitstring、およびbitarrayを試してみましたが、驚くべきことに、ビット演算に関しては Python の int が圧倒的に勝っているようです。私がグーグルで調べたものはすべて、このようなベクトル化された操作ではnumpyがはるかに高速になるはずだと言っています。どういうわけか間違ってnumpyを使用していますか? Python の組み込みの int 型を実際に改善するために使用できる別の Python ライブラリはありますか?
from timeit import timeit
import random
size = 10000
def int_to_bits(i):
result = []
for _ in range(size):
result.append(i % 2)
i >>= 1
return result
x = random.randrange(2**size)
y = random.randrange(2**size)
print(x.bit_length(), y.bit_length())
x_bits = int_to_bits(x)
y_bits = int_to_bits(y)
t = timeit(
stmt='a & b',
setup='a = %d; b = %d' % (x, y)
)
print("raw ints:", t)
t = timeit(
stmt='a & b',
setup=('import numpy;'
'a = numpy.array(%r, dtype=int);'
'b = numpy.array(%r, dtype=int)') % (x_bits, y_bits)
)
print('numpy int array:', t)
t = timeit(
stmt='a & b',
setup=('import numpy;'
'a = numpy.array(%r, dtype=bool);'
'b = numpy.array(%r, dtype=bool)') % (x_bits, y_bits)
)
print('numpy bool array:', t)
t = timeit(
stmt='a & b',
setup=('import numpy;'
'a = numpy.packbits(%r);'
'b = numpy.packbits(%r)') % (x_bits, y_bits)
)
print('numpy packed bits:', t)
t = timeit(
stmt='a & b',
setup=('import bitstring;'
'a = bitstring.BitString(%r);'
'b = bitstring.BitString(%r)') % (x_bits, y_bits)
)
print('bitstring:', t)
t = timeit(
stmt='a & b',
setup=('import bitarray;'
'a = bitarray.bitarray(%r);'
'b = bitarray.bitarray(%r)') % (x_bits, y_bits)
)
print('bitarray:', t)
結果:
10000 10000
raw ints: 0.29606562735373115
numpy int array: 7.400762747057885
numpy bool array: 1.1108355715984288
numpy packed bits: 1.3064737574273284
bitstring: 380.9796937642803
bitarray: 1.4451143449501842
編集:
Python の int/long に対する単一の操作が、numpy ビット配列全体に対するベクトル操作にどのように匹敵するかについて、多くの混乱があるようです。10,000 ビットの Python の int/long 値は、ビット マスクとして扱われる場合 (C/C++ で int や long と同じように & 演算子を使用)、長さ 10,000 の numpy bool 配列と直接比較できます。 2 つの異なる方法で表されますが、同じ数のビットが含まれます。numpy パック ビット配列、numpy int 配列、および他のライブラリのビット配列/文字列型の使用など、私が試した 10,000 ビットを表す他の方法にも同じことが当てはまります。それらはすべて、同じビットシーケンスで同じ関数を計算しているため、すべて比較可能です。ここで重要なのは、10,000 ビットすべてを表現できることと、それらに対してビット演算を実行できることです。
int_to_bits
Python の int/long 値が numpy bool 配列または numpy バイナリ値の int 配列と同じ情報を格納する方法についてまだ混乱している場合は、上記のコードの関数を参照してください。これは、Python int/long からビットを抽出する方法を示しています。これは、2 つの 10,000 ビット int に対して & 操作を実行することは、10,000 のブール値のリストまたは配列に対して要素ごとに実行することと基本的に同じであることを示しています。