You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Python生成大量n位二进制组合时出现的内存错误?

解决大位数二进制组合生成的内存错误问题

问题背景

我尝试用Python生成n位二进制0和1的所有组合,代码如下:

import itertools
from itertools import product
import pandas as pd
combinations=pd.DataFrame(product(range(2),repeat=k))

小k值时运行正常,但当k=31时,哪怕在128GB内存的64位Python环境下,还是触发了内存错误:

---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-5-97fdebdd2a99> in <module>
----> 1 pd.DataFrame(product(range(2),repeat=k))

~\anaconda3\lib\site-packages\pandas\core\frame.py in __init__(self, data, index, columns, dtype, copy)
    467             elif isinstance(data, abc.Iterable) and not isinstance(data, (str, bytes)):
    468                 if not isinstance(data, (abc.Sequence, ExtensionArray)):
--> 469                     data = list(data)
    470                 if len(data) > 0:
    471                     if is_list_like(data[0]) and getattr(data[0], "ndim", 1) == 1:

MemoryError:

想知道能不能拆分生成多个DataFrame再合并,或者有没有其他办法成功生成大量二进制组合?


解决方案

首先得算笔账:31位二进制组合总数是2^31 = 2147483648(超过21亿条),就算每条记录的31个整数只占124字节(按4字节/整数算),总数据量也接近266GB——这已经远超你的128GB内存,所以直接生成完整DataFrame肯定行不通。下面给你几个可行的思路:

1. 分批次生成并落地到磁盘,按需合并

把组合拆成小批次生成,每个批次保存为单独文件(CSV或更高效的Parquet),之后需要整体操作时再合并,这样每次只占用小部分内存。

示例代码:

import itertools
import pandas as pd
from itertools import islice

k = 31
total = 2 ** k
# 按内存情况调整批次大小,比如1000万条一批
batch_size = 10_000_000
combo_iter = itertools.product(range(2), repeat=k)

for idx in range(0, total, batch_size):
    # 从迭代器中截取当前批次的组合
    batch = list(islice(combo_iter, batch_size))
    df_batch = pd.DataFrame(batch)
    # 保存为CSV,也可以替换成Parquet格式节省空间
    df_batch.to_csv(f"binary_batch_{idx//batch_size}.csv", index=False)
    # 手动释放内存
    del df_batch, batch

后续合并所有批次:

import glob
import pandas as pd

# 读取所有批次文件
csv_list = glob.glob("binary_batch_*.csv")
# 分块合并,避免一次性加载所有文件
full_df = pd.concat((pd.read_csv(f) for f in csv_list), ignore_index=True)

2. 跳过DataFrame,直接迭代处理组合

如果你的后续操作不需要DataFrame的功能,完全可以直接遍历itertools.product的迭代器,逐个处理组合——这种方式几乎不占内存,因为每次只生成一个组合。

示例代码(写入文本文件):

import itertools

k = 31
# 打开文件并逐个写入组合
with open("all_binary_combinations.txt", "w") as f:
    for combo in itertools.product(range(2), repeat=k):
        f.write(",".join(map(str, combo)) + "\n")

3. 分治拆分生成,降低单次内存压力

把k位拆成前后两部分,比如前15位和后16位,先生成前半部分的所有组合,再对每个前半部分组合拼接后半部分的所有组合,分阶段处理:

import itertools
import pandas as pd

k = 31
split = 15  # 拆分位置,可根据内存调整
front_combos = list(itertools.product(range(2), repeat=split))
back_combos = list(itertools.product(range(2), repeat=k - split))

batch_size = 10_000_000
current_batch = []
batch_num = 0

for front in front_combos:
    for back in back_combos:
        current_batch.append(front + back)
        if len(current_batch) >= batch_size:
            # 保存当前批次
            pd.DataFrame(current_batch).to_csv(f"split_batch_{batch_num}.csv", index=False)
            current_batch = []
            batch_num += 1
# 处理剩余的组合
if current_batch:
    pd.DataFrame(current_batch).to_csv(f"split_batch_{batch_num}.csv", index=False)

4. 使用更高效的存储格式

如果一定要用DataFrame,推荐用Parquet格式保存批次文件——它比CSV节省30%-70%的空间,读写速度也更快,还支持分块存储:

import itertools
import pandas as pd
from itertools import islice

k = 31
batch_size = 10_000_000
combo_iter = itertools.product(range(2), repeat=k)

for idx in range(0, 2**k, batch_size):
    batch = list(islice(combo_iter, batch_size))
    pd.DataFrame(batch).to_parquet(f"binary_batch_{idx//batch_size}.parquet", index=False)
    del batch

合并时:

import glob
import pandas as pd

parquet_list = glob.glob("binary_batch_*.parquet")
full_df = pd.concat((pd.read_parquet(f) for f in parquet_list), ignore_index=True)

内容的提问来源于stack exchange,提问作者LawLietLai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:57:33