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

Posted

技术标签:

【中文标题】具有 1 位条目的 numpy 布尔数组【英文标题】:numpy boolean array with 1 bit entries 【发布时间】:2011-08-01 21:49:58 【问题描述】:

在 numpy 中有没有办法创建一个布尔数组,每个条目只使用 1 位?

标准的np.bool类型是1字节,但是这样我使用了8倍的所需内存。

在 Google 上我发现 C++ 有 std::vector<bool>

【问题讨论】:

possible to do this with numpy's native functions 【参考方案1】:

你想要一个bitarray:

高效的布尔数组——C 扩展

这个模块提供了一个对象类型,它可以有效地表示一个布尔数组。位数组是序列类型,其行为与通常的列表非常相似。八位由一个连续的内存块中的一个字节表示。用户可以在两种表示之间进行选择;小端和大端。所有功能都用 C 语言实现。提供了访问机器表示的方法。这在需要对二进制文件进行位级访问时很有用,例如可移植位图图像文件 (.pbm)。此外,在处理使用可变位长编码的压缩数据时,您可能会发现此模块很有用...

【讨论】:

谢谢!它看起来非常有用,这里唯一缺少的是 I/O 例程将所有文件加载到内存中,而使用 'numpy.load' 我可以使用内存映射。 将这个 bityarray 转换回 numpy 数组是否容易?你能添加一个小例子来证明这一点吗?【参考方案2】:

您可能想看看bitstring(文档here)。

如果您从文件创建ConstBitArrayConstBitStream,那么它将使用mmap 而不会将其加载到内存中。在这种情况下,它不会是可变的,因此如果您想进行更改,则必须将其加载到内存中。

例如创建而不加载到内存中:

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

>>> b = bitstring.ConstBitStream(a_file_object)

【讨论】:

因为我只写一次,所以我不需要修改我的数据。【参考方案3】:

为此,您可以使用 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

【讨论】:

作为附录,我正在努力改进这个答案:github.com/numpy/numpy/pull/10855。目标是使 packbits 和 unpackbits 完全可逆而无需重塑。 @MadPhysicist 这会很棒。谢谢你这样做。完成后,请写下您自己的答案或编辑我的答案。 @SalvadorDali 好像是 PR made it to master 这里唯一的问题是压缩数组意味着在内存中包含压缩和未压缩的数组,但有时你根本没有足够的内存来包含更大的内存,这就是你想要的原因使用打包格式 @SalvadorDali。在你提出要约将近 3 年后,我终于用 PR 的信息更新了你的答案:)

以上是关于具有 1 位条目的 numpy 布尔数组的主要内容,如果未能解决你的问题,请参考以下文章

在 numpy 中从具有索引的 2D 矩阵构建 3D 布尔矩阵

用布尔数组索引 SciPy 稀疏矩阵

只有整数、切片 (`:`)、省略号 (`...`)、numpy.newaxis (`None`) 和整数或布尔数组是有效的索引

通过布尔掩码数组选择numpy数组的元素

如何在 numpy 中创建布尔数组

NumPy 数组切片索引