具有1位条目的numpy布尔数组

56 投票
3 回答
36915 浏览
提问于 2025-04-16 15:22

有没有办法在numpy中创建一个布尔值数组,每个元素只用1个比特位?

标准的np.bool类型占用1个字节,但这样我就用了8倍的内存。

我在谷歌上发现C++有一个叫做std::vector<bool>的东西。

3 个回答

24

你想要一个bitarray

高效的布尔数组 - C扩展

这个模块提供了一种对象类型,可以高效地表示布尔值的数组。bitarray就像普通的列表一样,是一种序列类型。八个比特(bit)会被一个字节(byte)连续存储在内存中。用户可以选择两种表示方式:小端(little-endian)和大端(big-endian)。所有功能都是用C语言实现的。这个模块还提供了访问机器表示的方法。当你需要对二进制文件进行比特级别的访问时,比如可移植位图图像文件(.pbm),这个模块会很有用。此外,当处理使用可变比特长度编码的压缩数据时,你也可能会发现这个模块很实用...

41

要实现这个功能,你可以使用numpy库里的packbitsunpackbits这两个函数。

import numpy as np
# original boolean array
A1 = np.array([
    [0, 1, 1, 0, 1],
    [0, 0, 1, 1, 1],
    [1, 1, 1, 1, 1],
], dtype=bool)

# packed data
A2 = np.packbits(A1, axis=None)

# checking the size
print(len(A1.tostring())) # 15 bytes
print(len(A2.tostring())) #  2 bytes (ceil(15/8))

# reconstructing from packed data. You need to resize and reshape
A3 = np.unpackbits(A2, count=A1.size).reshape(A1.shape).view(bool)

# and the arrays are equal
print(np.array_equal(A1, A3)) # True

在numpy 1.17.0之前,第一个函数使用起来很简单,但要把数据恢复成原来的样子就需要做一些额外的处理。下面是一个例子:

import numpy as np
# original boolean array
A1 = np.array([
    [0, 1, 1, 0, 1],
    [0, 0, 1, 1, 1],
    [1, 1, 1, 1, 1],
], dtype=np.bool)

# packed data
A2 = np.packbits(A1, axis=None)

# checking the size
print(len(A1.tostring())) # 15 bytes
print(len(A2.tostring())) #  2 bytes (ceil(15/8))

# reconstructing from packed data. You need to resize and reshape
A3 = np.unpackbits(A2, axis=None)[:A1.size].reshape(A1.shape).astype(np.bool)

# and the arrays are equal
print(np.array_equal(A1, A3)) # True
15

你可以看看这个叫做 bitstring 的工具(文档在 这里)。

如果你从一个文件创建 ConstBitArrayConstBitStream,那么它会使用 mmap,这样就不会把文件内容加载到内存里。在这种情况下,你不能修改它,所以如果你想做更改,就必须把它加载到内存中。

比如说,如何在不加载到内存的情况下创建:

>>> a = bitstring.ConstBitArray(filename='your_file')

或者

>>> b = bitstring.ConstBitStream(a_file_object)

撰写回答