Python读取GB级CSV文件内存溢出怎么办_Pandas分块读取Chunk处理
pandas.read_csv() 读GB级CSV爆内存因默认全量加载+自动类型推断,导致内存占用达原始文件2–3倍;应指定usecols、dtype、index_col=False,并用chunksize分块迭代处理,避免累积chunk。
为什么直接用 pandas.read_csv() 读GB级CSV会爆内存
因为 pandas.read_csv() 默认把整个文件一次性加载进内存,生成完整的 DataFrame。哪怕你只想要其中几列或几行,它也得先解析全部文本、类型推断、构建索引——对2GB CSV,实际内存占用常达4–6GB,远超物理内存时就触发 MemoryError。
根本问题不在数据量本身,而在于「全量加载 + 默认 dtype 推断」这个行为。尤其当文件含大量字符串、缺失值或混合类型列时,内存放大效应更明显。
- 避免用
dtype='string'或未指定dtype——改用明确类型如dtype={'col1': 'category', 'col2': 'float32'} - 禁用索引:加参数
index_col=False,除非真需要行号作为索引 - 跳过无用列:
usecols必须显式指定,比读完再删列省 30%+ 内存
用 chunksize 分块读取的正确姿势
chunksize 不是“自动帮你省内存”的开关,它只是返回一个 TextFileReader 迭代器;真正省内存靠的是你**不累积所有 chunk**,而是逐块处理、立即释放。
常见错误是写成 chunks = list(pd.read_csv(..., chunksize=10000))——这等于又全装进内存了。
Krisp
AI噪音消除工具
- 正确做法:用
for chunk in pd.read_csv(..., chunksize=5000)循环,每块处理完立刻丢弃引用 -
chunksize值不是越大越好:5000–20000 行较稳妥;太大仍可能单块溢出,太小则 I/O 开销上升 - 若需全局统计(如总行数、各列最大值),在循环中用变量累加,别存 chunk
for chunk in pd.read_csv('big.csv', chunksize=10000, usecols=['id', 'amount'], dtype={'amount': 'float32'}):
total += chunk['amount'].sum()
# 处理逻辑...
del chunk # 显式删除,加速 GC
哪些操作必须在分块内完成,不能拖到后面
一旦离开 for chunk in ... 循环,chunk 就该被回收。任何依赖原始 chunk 数据的后续操作,如果没在循环里做完,基本等于白读。
- 过滤:用
chunk[chunk['status'] == 'done'],别想着“先读完再统一 filter” - 聚合:
chunk.groupby('city')['sales'].sum()→ 每块输出部分结果,最后再 merge 或 sum - 写入新文件:用
mode='a'追加写,别攒着一起to_csv - 建模训练:用
partial_fit(如SGDClassifier)或流式特征提取,别拼全量X_train
比 chunksize 更轻量的替代方案
如果只是简单遍历、计数、抽样或条件扫描,pandas 仍是重武器。纯文本流处理更快、更省内存:
- 用内置
csv模块:适合结构清晰、无复杂 quoting/escape 的场景 -
dask.dataframe.read_csv():能自动并行和延迟计算,但启动开销大,小文件反而慢 -
polars.read_csv(..., streaming=True):Rust 底层,流式解析极快,内存占用稳定,推荐用于新项目
注意:polars 对中文路径、特殊编码(如 GBK)支持弱于 pandas,读取前务必确认 encoding 参数是否生效。