分块读取是处理超大CSV的唯一可行路径,必须用chunksize返回TextFileReader迭代器逐块加载DataFrame,避免全量加载触发MemoryError;需从1000起步实测内存、显式指定dtype、就地写入而非累积concat,并警惕跨块逻辑失效。

分块读取和处理是唯一可行路径,硬加载全量数据必然触发 MemoryError。
用 chunksize 参数控制每次读入的行数
直接调用 pd.read_csv() 时传入 chunksize(整数),它不会返回 DataFrame,而是返回一个 TextFileReader 迭代器。每次 next() 或循环中获取的都是独立的 DataFrame 块,内存只保留当前块。
- 值不是越大越好:设为 10000 可能仍爆内存,建议从 1000 起步,观察任务管理器或
psutil.Process().memory_info().rss实时监控 - 注意列类型推断问题:每块单独 infer 类型可能导致不一致,可在
read_csv()中用dtype显式指定,或先用小样本跑一次df.dtypes.to_dict()固定类型 - 若需跳过头部/尾部行,
skiprows和skipfooter在分块模式下行为异常,应改用usecols或预处理文件
避免在块循环中累积结果到列表再拼接
常见错误是把每块处理结果 .append() 到 list,最后 pd.concat(list) —— 这会把所有块重新载入内存,前功尽弃。
- 正确做法:对每块就地处理并立即写入磁盘,例如用
to_csv(..., mode='a', header=False)追加到输出文件 - 若必须汇总统计(如求总和、计数),只维护几个标量变量,而非 DataFrame 或 Series;例如
total_sum += chunk['col'].sum() - 若要用
groupby全局聚合,不能直接chunk.groupby(...).sum(),得先保存各块中间结果(如字典{key: partial_sum}),最后合并再计算
分块写入时注意索引与文件头管理
用 to_csv() 分批写入同一文件时,header=True 必须仅对第一块启用,否则每块都写列名,后续读取会出错。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 推荐写法:
for i, chunk in enumerate(reader): chunk.to_csv('out.csv', mode='a', header=(i==0), index=False) - 若原始数据含索引列且需保留,确保
index_col在read_csv()中已指定,否则分块后索引会重置为 0..n,丢失原始顺序信息 - 写入时若遇到
PermissionError: [Errno 13] Permission denied,大概率是文件被 Excel 或其他程序占用,关闭相关进程再试
更轻量的替代方案:Dask 或 Polars 的 lazy 模式
当逻辑复杂、需要链式操作(如多层 merge、嵌套 apply)且 Pandas 分块代码变得难维护时,可切换工具,但要注意迁移成本。
-
dask.dataframe.read_csv()自动分块 + 延迟执行,.compute()才真正运行,适合中等规模(GB 级)且 CPU 富余场景 -
polars.scan_csv()返回 LazyFrame,语法接近 Pandas,执行效率更高,但不支持全部 Pandas API(如str.extractall) - 二者都无法绕过磁盘 I/O 瓶颈;SSD 比 HDD 快 3–5 倍,如果卡在读文件阶段,换工具不如换硬件
真正棘手的从来不是“怎么分块”,而是分块后如何保证业务逻辑语义不变——比如窗口函数跨块失效、时间序列排序错乱、去重漏掉跨块重复项。这些必须根据具体需求逐条验证,没有通用解法。

















