4

ブール値を格納するよりコンパクトな方法を探しています。numpy は、1 つのブール値を格納するために内部的に 8 ビットを必要としますが、np.packbitsそれらをパックできるようにします。これはかなりクールです。

問題は、ブール値の32e6 バイト配列を 4e6 バイト配列にパックするには、最初に256e6 バイトを費やしてブール配列を int 配列に変換する必要があることです。

In [1]: db_bool = np.array(np.random.randint(2, size=(int(2e6), 16)), dtype=bool)
In [2]: db_int = np.asarray(db_bool, dtype=int)
In [3]: db_packed = np.packbits(db_int, axis=0)
In [4]: db.nbytes, db_int.nbytes, db_packed.nbytes
Out[5]: (32000000, 256000000, 4000000)

それについて numpy トラッカーで開かれた 1 年前の問題があります ( 参照 https://github.com/numpy/numpy/issues/5377 ) 。

誰かが解決策/より良い回避策を持っていますか?

正しい方法で実行しようとしたときのトレースバック:

In [28]: db_pb = np.packbits(db_bool)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-28-3715e167166b> in <module>()
----> 1 db_pb = np.packbits(db_bool)
TypeError: Expected an input array of integer data type
In [29]:

PS: bitarray を試してみますが、純粋な numpy で取得する必要があります。

4

2 に答える 2

5

ブール配列をネイティブintdtype (x86_64 では 64 ビット) に変換する必要はありません。として表示することで、ブール配列のコピーを回避できますnp.uint8。これも、要素ごとに 1 バイトを使用します。

packed = np.packbits(db_bool.view(np.uint8))

unpacked = np.unpackbits(packed)[:db_bool.size].reshape(db_bool.shape).view(np.bool)

print(np.all(db_bool == unpacked))
# True

また、1 年以上前 (numpy v1.10.0 以降)のこのコミットnp.packbitsの時点で、boolean 配列で直接動作するようになりました。

于 2015-12-29T16:54:51.310 に答える
4

ちょうど昨日、C++ と比較して、Python でビットを処理する方法について初心者に質問に答えました。速度が向上しないことを警告した後、内部で Python の bytearray オブジェクトを使用して単純な "bitarray" をスケッチしました。

これは決して高速ではありませんが、配列ビットを操作する必要がなくなり、出力だけが必要な場合は、Python コードで変換を完全に制御できるため、これで十分です。それ以外の場合は、静的型をヒントするだけで、Cython と同じコードを実行できます。おそらく、bytearray の代わりに dtype=int8 の np 配列を使用することをお勧めします。

class BitArray(object):
    def __init__(self, length):
        self.values = bytearray(b"\x00" * (length // 8 + (1 if length % 8  else 0)))
        self.length = length

    def __setitem__(self, index, value):
        value = int(bool(value)) << (7 - index % 8)
        mask = 0xff ^ (7 - index % 8)
        self.values[index // 8] &= mask
        self.values[index // 8] |= value
    def __getitem__(self, index):
        mask = 1 << (7 - index % 8)
        return bool(self.values[index // 8] & mask)

    def __len__(self):
        return self.length

    def __repr__(self):
        return "<{}>".format(", ".join("{:d}".format(value) for value in self))

このコードは最初にここに投稿されました: Is there a builtin bitset in Python that's similar to the std::bitset from C++?

于 2015-12-29T12:59:39.563 に答える