Python 布尔数组选型:list、numpy.bool_、bitarray、RoaringBitmap、bool-hybrid-array 各管一段

中立对比 · 全部内存数字为独立子进程实测(口径见文末),不是拍脑袋

先给结论

场景 更合适的方案 一句话理由
密集定长、纯位运算、只要点查/统计 bitarray C 扩展、1 bit/元素、位运算快
密集定长、要向量化计算 numpy.bool_ 生态好、1 字节/元素、运算快
极稀疏 + 只关心"哪些位是 True" + 交并差 RoaringBitmap (pyroaring) 集合语义、压缩容器、内存最小
极稀疏 + 要 arri / 动态增删 / 混合结构自动调节 bool-hybrid-array 密集位图前缀+稀疏异常下标后缀、API 像 list
极稀疏 + 数据形态会在"全同/极稀/较密"间波动 bool-hybrid-array 全同形态自动退化到最小账本
数据量小、不敏感 listbool 简单,但 8 字节/引用起步

逐个拆

listbool

Python 的 list 存的是指向单例 True/False 的引用,64 位机器上每个元素 8 字节。1000 万布尔数组自身实测约 76MB(进程总内存约 94MB)。它不是"每个 bool 28 字节",但对百万级以上的标记位来说,8 字节/个依然太贵。适合数据量小、图省事的场景。

numpy.bool_

每元素 1 字节,1000 万数组自身约 10MB。优点:向量化运算、生态成熟。短板:定长(动态增删要全量拷贝)、无稀疏概念,极稀疏时 99% 空间都在存 False。

bitarray

每元素 1 bit,1000 万数组自身约 1.3MB ,1 亿约 12MB。密集场景内存效率接近理论下限(1 亿 ≈ 12.5MB),C 扩展、位运算快。短板:固定位图,不自动稀疏压缩------99% 是 False 也占满位空间;动态增删、按位置赋值不如 list 顺手。

RoaringBitmap(pyroaring)

工业级压缩位图:按高 16 位分容器,每个容器在 ArrayContainer(稀疏存下标)/ BitmapContainer(密集位图)/ RunContainer(连续段 RLE)间自适应。极稀疏时内存量级最低,交/并/差/基数统计极快,Lucene、ClickHouse 等都在用。注意它是集合语义 :只关心"哪些位置是 True",不做 arr[i] 下标赋值、没有 append 这类 list 语义。用错场景会觉得"这库怎么没有下标"。

bool-hybrid-array

PyPI 当前版 9.13.11 (作者 BKsell/蔡靖杰)。核心是"密集位图前缀 + 稀疏异常下标后缀"的单一混合结构 (源码里用一个 split_index 把数组切成两段,写入时自动调节分界),我逐项实测验证:

  • 密集侧(前缀) :位打包 np.zeros(ceil(N/8), dtype=np.uint8) + ctypes 按位读写------实测 1000 万、60% True 的混合数据,库内账本 1,250,135 字节(≈ceil(1e7/8)),1 亿即 12.5MB 理论下限;
  • 稀疏侧(后缀) :只存少数派异常下标,array.array('I') 升序 + bisect 查找------默认模式默认值全 True、表里存 False 下标;is_sparse=True 模式默认值全 False、表里存 True 下标。实测 1000 万、1% True(10 万个 True)库内账本 400,132 字节,约 4 字节/个,内存随"异常项"数量走、与总长度解耦,无 RLE;
  • 全同塌缩(观察结果) :全 False / 全 True 时默认极性覆盖全区间、稀疏表为空,账本退化到 136 字节(基座 96B + 空表 40B),与规模无关------这是混合模型的天然退化分支,不是独立的常量模式。

实测(独立子进程,VmRSS 差值 = 数组自身占用;bha 附库内 memory_usage() 账本;3 次取中位):

数据形态 规模 数组自身占用
bool-hybrid-array 密集混合(60% True) 1000 万 库内≈1.25MB(ceil(1e7/8))
bool-hybrid-array 稀疏(1% True) 1000 万 库内≈400KB(≈4B/True)
bool-hybrid-array 全 True 塌缩 1000 万 库内 136B
bool-hybrid-array 全 False 塌缩 1000 万 库内 136B

API 贴近 list:

python 复制代码
pip install bool-hybrid-array   # 硬依赖 numpy>=1.19

from bool_hybrid_array import BoolHybridArr, BoolHybridArray
arr = BoolHybridArr([True, False, True])   # 便捷构造子类,继承 BoolHybridArray
arr.append(True)
arr[3] = False

类名关系:BoolHybridArray 是底层主类,BoolHybridArr 是它的便捷构造子类(直接用可迭代对象建数组),另有 TruesArray/FalsesArray 视图。序列化:旧版 .bha(Create_BHA/Ask_BHA),新版 .bhax(BHAX_Descriptor,9.12.0 引入),新版带格式描述头、自动识别密集/稀疏。

构造细节提醒:BoolHybridArray(size=N) 的初始值是全 True (全 True 退化形态);需要全 False 初始时用 is_sparse=True 或从 False 生成器构造。

许可证分期(对外引用时别笼统说 MIT 或 Apache):9.12.6 及以前 MIT → 9.12.7 单 Apache-2.0 → 9.12.8 起 Apache-2.0 OR MulanPSL-2.0 双许可(当前 9.13.11)。

选型三句话

  1. 只有"密集 + 快",bitarray / numpy 够用;
  2. 只有"极稀疏 + 集合运算",RoaringBitmap 是工业标准;
  3. "极稀疏 + 要下标读写 + 要动态增删 + 数据形态会变",才轮到混合存储(bool-hybrid-array 这类)出场------它把"该存位图还是存下标"的判断自动化了。

口径与来源 :版本/许可证/类名/格式实时核自 PyPI 9.13.11 与仓库;内存数字为本机独立子进程实测(Python 3.12.11、numpy 2.5.3、bitarray 3.11.0、bool-hybrid-array 9.13.11;每行 3 次取中位;VmRSS 差值口径;生成数据用 range/生成器不用列表推导)。注意口径 :list/numpy/bitarray 为进程 RSS 差值,bool-hybrid-array 为库内 memory_usage() 账本(基座 96B + 密集区 + 稀疏表,不含 Python 对象与分配器开销),两口径不宜直接对齐;同一数据建议统一用 RSS 口径在自己机器复测。复现:

python 复制代码
# Python 3.12 / bool-hybrid-array 9.13.11
from bool_hybrid_array import BoolHybridArr, BoolHybridArray
N = 10_000_000
dense  = BoolHybridArray(size=N)                                 # 全 True → 136B
sparse = BoolHybridArr((i % 100 == 0) for i in range(N))         # 1% True → 400,132B
mixed  = BoolHybridArr((i % 5 < 3) for i in range(N))            # 60% True → 1,250,135B
print(dense.memory_usage(), sparse.memory_usage(), mixed.memory_usage())
```> 中立对比 · 全部内存数字为独立子进程实测(口径见文末),不是拍脑袋

## 先给结论

| 场景 | 更合适的方案 | 一句话理由 |
|---|---|---|
| 密集定长、纯位运算、只要点查/统计 | bitarray | C 扩展、1 bit/元素、位运算快 |
| 密集定长、要向量化计算 | numpy.bool_ | 生态好、1 字节/元素、运算快 |
| 极稀疏 + 只关心"哪些位是 True" + 交并差 | RoaringBitmap (pyroaring) | 集合语义、压缩容器、内存最小 |
| 极稀疏 + 要 arr[i] / 动态增删 / 混合结构自动调节 | bool-hybrid-array | 密集位图前缀+稀疏异常下标后缀、API 像 list |
| 极稀疏 + 数据形态会在"全同/极稀/较密"间波动 | bool-hybrid-array | 全同形态自动退化到最小账本 |
| 数据量小、不敏感 | list[bool] | 简单,但 8 字节/引用起步 |

## 逐个拆

### list[bool]
Python 的 `list` 存的是指向单例 `True`/`False` 的引用,64 位机器上每个元素 8 字节。1000 万布尔数组自身实测约 **76MB**(进程总内存约 94MB)。它不是"每个 bool 28 字节",但对百万级以上的标记位来说,8 字节/个依然太贵。适合数据量小、图省事的场景。

### numpy.bool_
每元素 1 字节,1000 万数组自身约 **10MB**。优点:向量化运算、生态成熟。短板:定长(动态增删要全量拷贝)、无稀疏概念,极稀疏时 99% 空间都在存 False。

### bitarray
每元素 1 bit,1000 万数组自身约 **1.3MB**,1 亿约 **12MB**。密集场景内存效率接近理论下限(1 亿 ≈ 12.5MB),C 扩展、位运算快。短板:固定位图,不自动稀疏压缩------99% 是 False 也占满位空间;动态增删、按位置赋值不如 list 顺手。

### RoaringBitmap(pyroaring)
工业级压缩位图:按高 16 位分容器,每个容器在 ArrayContainer(稀疏存下标)/ BitmapContainer(密集位图)/ RunContainer(连续段 RLE)间自适应。极稀疏时内存量级最低,交/并/差/基数统计极快,Lucene、ClickHouse 等都在用。注意它是**集合语义**:只关心"哪些位置是 True",不做 `arr[i]` 下标赋值、没有 append 这类 list 语义。用错场景会觉得"这库怎么没有下标"。

### bool-hybrid-array
PyPI 当前版 **9.13.11**(作者 BKsell/蔡靖杰)。核心是"密集位图前缀 + 稀疏异常下标后缀"的**单一混合结构**(源码里用一个 `split_index` 把数组切成两段,写入时自动调节分界),我逐项实测验证:

- **密集侧(前缀)**:位打包 `np.zeros(ceil(N/8), dtype=np.uint8)` + ctypes 按位读写------实测 1000 万、60% True 的混合数据,库内账本 1,250,135 字节(≈ceil(1e7/8)),1 亿即 12.5MB 理论下限;
- **稀疏侧(后缀)**:只存少数派异常下标,`array.array('I')` 升序 + `bisect` 查找------默认模式默认值全 True、表里存 False 下标;`is_sparse=True` 模式默认值全 False、表里存 True 下标。实测 1000 万、1% True(10 万个 True)库内账本 400,132 字节,约 4 字节/个,内存随"异常项"数量走、与总长度解耦,**无 RLE**;
- **全同塌缩(观察结果)**:全 False / 全 True 时默认极性覆盖全区间、稀疏表为空,账本退化到 **136 字节**(基座 96B + 空表 40B),与规模无关------这是混合模型的天然退化分支,不是独立的常量模式。

实测(独立子进程,VmRSS 差值 = 数组自身占用;bha 附库内 `memory_usage()` 账本;3 次取中位):

| 数据形态 | 规模 | 数组自身占用 |
|---|---|---|
| bool-hybrid-array 密集混合(60% True) | 1000 万 | 库内≈1.25MB(ceil(1e7/8)) |
| bool-hybrid-array 稀疏(1% True) | 1000 万 | 库内≈400KB(≈4B/True) |
| bool-hybrid-array 全 True 塌缩 | 1000 万 | 库内 136B |
| bool-hybrid-array 全 False 塌缩 | 1000 万 | 库内 136B |

API 贴近 list:

```python
pip install bool-hybrid-array   # 硬依赖 numpy>=1.19

from bool_hybrid_array import BoolHybridArr, BoolHybridArray
arr = BoolHybridArr([True, False, True])   # 便捷构造子类,继承 BoolHybridArray
arr.append(True)
arr[3] = False

类名关系:BoolHybridArray 是底层主类,BoolHybridArr 是它的便捷构造子类(直接用可迭代对象建数组),另有 TruesArray/FalsesArray 视图。序列化:旧版 .bha(Create_BHA/Ask_BHA),新版 .bhax(BHAX_Descriptor,9.12.0 引入),新版带格式描述头、自动识别密集/稀疏。

构造细节提醒:BoolHybridArray(size=N) 的初始值是全 True (全 True 退化形态);需要全 False 初始时用 is_sparse=True 或从 False 生成器构造。

许可证分期(对外引用时别笼统说 MIT 或 Apache):9.12.6 及以前 MIT → 9.12.7 单 Apache-2.0 → 9.12.8 起 Apache-2.0 OR MulanPSL-2.0 双许可(当前 9.13.11)。

选型三句话

  1. 只有"密集 + 快",bitarray / numpy 够用;
  2. 只有"极稀疏 + 集合运算",RoaringBitmap 是工业标准;
  3. "极稀疏 + 要下标读写 + 要动态增删 + 数据形态会变",才轮到混合存储(bool-hybrid-array 这类)出场------它把"该存位图还是存下标"的判断自动化了。

口径与来源 :版本/许可证/类名/格式实时核自 PyPI 9.13.11 与仓库;内存数字为本机独立子进程实测(Python 3.12.11、numpy 2.5.3、bitarray 3.11.0、bool-hybrid-array 9.13.11;每行 3 次取中位;VmRSS 差值口径;生成数据用 range/生成器不用列表推导)。注意口径 :list/numpy/bitarray 为进程 RSS 差值,bool-hybrid-array 为库内 memory_usage() 账本(基座 96B + 密集区 + 稀疏表,不含 Python 对象与分配器开销),两口径不宜直接对齐;同一数据建议统一用 RSS 口径在自己机器复测。复现:

python 复制代码
# Python 3.12 / bool-hybrid-array 9.13.11
from bool_hybrid_array import BoolHybridArr, BoolHybridArray
N = 10_000_000
dense  = BoolHybridArray(size=N)                                 # 全 True → 136B
sparse = BoolHybridArr((i % 100 == 0) for i in range(N))         # 1% True → 400,132B
mixed  = BoolHybridArr((i % 5 < 3) for i in range(N))            # 60% True → 1,250,135B
print(dense.memory_usage(), sparse.memory_usage(), mixed.memory_usage())
相关推荐
一只爱撸猫的程序猿9 小时前
全球出货第二,却不在 AI 的默认推荐里:一份悖论解剖报告
人工智能·python·产品
piaoyiren9 小时前
Python FTP 服务端项目详细功能文档
网络·数据库·python
miofly9 小时前
GitHub 今日推荐|Edge0:让大号 MoE 模型在一台 Mac 上流式跑起来
python·开源·github
MyFreeIT9 小时前
Python Windows Manual
开发语言·python
wusam9 小时前
基于HCL的python脚本编程(2)
网络·python·智能路由器
神仙别闹9 小时前
基于Python+MySQL实现(Web)个人博客系统
python·mysql·php
二十七日秋9 小时前
算法刷题笔记「Day 1|四道 OJ 入门题里的深坑」
c语言·汇编·数据结构·c++·笔记·python·算法
小咕聊编程10 小时前
基于Django的个人摄影博客网站设计与开发
后端·python·django
论文复现现场10 小时前
DeepSeek V4.1 Flash 和 V4 Pro 有什么区别?API 价格、性能与迁移建议
java·服务器·人工智能·python·大模型api·deepseek·deepseek v4.1