根本解法是用 chunksize 参数使 pandas.read_csv() 返回 TextFileReader 对象,分块读取并边读边处理,内存峰值仅取决于单块大小;需注意 dtype 一致性、na_values 设置、避免循环中多次 pd.concat 等关键细节。

用 chunksize 参数控制内存占用
直接用 pandas.read_csv() 读几个G的CSV,大概率触发 MemoryError。根本解法不是“优化代码”,而是跳过一次性加载——靠 chunksize 让 pandas 返回一个可迭代的 TextFileReader 对象,每次只读固定行数(比如 50000 行)。
关键点:这不是“分批读完再合并”,而是边读边处理,内存峰值只取决于单块大小。
-
chunksize值不是越大越好:设为 100000 可能仍爆内存,建议从 10000–50000 试起,观察任务管理器/htop 的 RSS 占用 - 不能直接对
TextFileReader调用.shape或.head(),会报AttributeError;必须先for chunk in reader:进入循环 - 如果 CSV 有行首注释(如
# generated at 2024-01-01),需加comment='#',否则第一块可能解析错列数
处理分块时的列类型与缺失值一致性
不同 chunk 的同一列,pandas 默认会各自推断 dtype,可能导致有的 chunk 是 int64、有的是 object(比如某块该列全为空),后续 pd.concat() 会失败或隐式转换出错。
- 强制指定
dtype:用字典传入,如dtype={'user_id': 'Int64', 'amount': 'float32'};Int64(大写 I)支持 NaN,比int64更安全 - 统一
na_values和keep_default_na:比如原始数据用'NULL'表示空,就得写na_values=['NULL'], keep_default_na=False,否则部分 chunk 可能把字符串'NULL'当成有效值 - 如果要用
pd.concat(chunks, ignore_index=True)合并所有块,确保每块列名、列顺序完全一致;列名含空格或特殊字符时,提前用names=...显式指定,别依赖 header 自动读取
避免常见性能陷阱:不要在循环里反复 pd.concat()
有人写成 result = pd.DataFrame(); for chunk in reader: result = pd.concat([result, chunk]),这是典型反模式——每次 concat 都要复制整个 DataFrame,时间复杂度 O(n²),10GB 文件可能跑一整天。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
立即学习“Python免费学习笔记(深入)”;
- 正确做法:把每个
chunkappend 到 list,最后一次pd.concat(),如chunks = []; for chunk in reader: chunks.append(chunk); full_df = pd.concat(chunks, ignore_index=True) - 如果最终不需要全量数据(比如只统计 sum、mean),就别存 chunk,直接累加:
total_sum = 0; for chunk in reader: total_sum += chunk['value'].sum() - 想边读边写入数据库?用
chunk.to_sql(..., if_exists='append'),但注意 SQLite 不支持并发写,PostgreSQL 需配好连接池
当 chunksize 无法满足需求时的备选方案
某些场景下,即使分块也扛不住:比如 CSV 列极宽(上千列)、某列含超长文本(JSON 字符串)、或需要随机访问某行——这时 chunksize 仍是起点,但得叠加其他手段。
- 用
usecols只读必要列,例如usecols=['id', 'timestamp', 'status'],能减少 70%+ 内存 - 对时间列用
parse_dates=['timestamp']+date_parser指定pd.to_datetime的格式(如format='%Y-%m-%d %H:%M:%S'),避免默认解析慢且占内存 - 实在卡死,换
dask.dataframe.read_csv():API 类似 pandas,自动分块+延迟计算,适合探索性分析;但注意它不保证单次操作原子性,调试时.compute()才真正执行
最易被忽略的是:分块读取时,skiprows 和 nrows 不能同时用,且 skiprows 若传函数,会在每个 chunk 都调用一次——本想跳过前 10 行,结果每块都跳,数据全乱。真要跳行,用 skiprows=range(1, 11) 这种明确列表。

















