打包布尔数组需要通过 int (numpy 1.8.2)
packing boolean array needs go throught int (numpy 1.8.2)
我正在寻找更紧凑的布尔值存储方式。
numpy 内部需要 8 位来存储一个布尔值,但 np.packbits
允许打包
他们,太棒了。
问题是要打包一个 4e6 字节 数组 32e6 字节 布尔数组我们需要先花费 256e6字节将boolean数组转换为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 跟踪器中打开了一个一年前的问题(Cf.
https://github.com/numpy/numpy/issues/5377)
有人 solution/better 解决方法吗?
当我们尝试以正确的方式进行时的回溯:
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 中得到它。
就在昨天,我回答了一个新手关于如何处理 Python 中的位的问题 - 与 C++ 相比。在警告不会有速度提升之后,我 sketched-up 一个天真的 "bitarray" 使用内部 Python 的 bytearray 对象。
这绝对不是很快 - 但如果您不再对数组位进行操作,而只是想要输出,也许它就足够了 - 因为您可以完全控制 Python 代码转换。否则,您可以尝试仅提示静态类型和 运行 与 Cython 相同的代码,并且您可能希望使用 dtype=int8 的 np 数组而不是 bytearray:
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))
此代码最初发布于此:
无需将您的布尔数组转换为本机 int
dtype(在 x86_64 上将是 64 位)。您可以通过将布尔数组视为 np.uint8
来避免复制布尔数组,每个元素也使用一个字节:
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
另外,np.packbits
从一年多前的 this commit 开始(numpy v1.10.0 和更新版本)现在应该可以直接处理布尔数组。
我正在寻找更紧凑的布尔值存储方式。
numpy 内部需要 8 位来存储一个布尔值,但 np.packbits
允许打包
他们,太棒了。
问题是要打包一个 4e6 字节 数组 32e6 字节 布尔数组我们需要先花费 256e6字节将boolean数组转换为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 跟踪器中打开了一个一年前的问题(Cf. https://github.com/numpy/numpy/issues/5377)
有人 solution/better 解决方法吗?
当我们尝试以正确的方式进行时的回溯:
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 中得到它。
就在昨天,我回答了一个新手关于如何处理 Python 中的位的问题 - 与 C++ 相比。在警告不会有速度提升之后,我 sketched-up 一个天真的 "bitarray" 使用内部 Python 的 bytearray 对象。
这绝对不是很快 - 但如果您不再对数组位进行操作,而只是想要输出,也许它就足够了 - 因为您可以完全控制 Python 代码转换。否则,您可以尝试仅提示静态类型和 运行 与 Cython 相同的代码,并且您可能希望使用 dtype=int8 的 np 数组而不是 bytearray:
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))
此代码最初发布于此:
无需将您的布尔数组转换为本机 int
dtype(在 x86_64 上将是 64 位)。您可以通过将布尔数组视为 np.uint8
来避免复制布尔数组,每个元素也使用一个字节:
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
另外,np.packbits
从一年多前的 this commit 开始(numpy v1.10.0 和更新版本)现在应该可以直接处理布尔数组。