chunksize需按实际内存反推:先用nrows=5000试读,计算memory_usage(deep=True)得样本内存,再按目标内存比例换算;同时必须配合dtype降级、usecols筛选、及时del chunk和gc.collect(),四者联动才有效。

pd.read_csv() 加载就爆内存,怎么设 chunksize 才有效?
chunksize 不是设个整数就管用的。它只控制行数,不控制内存占用——一行含 500 字符的 object 列,可能比 100 行全 int32 还吃内存。
- 先试读小样本:
pd.read_csv(filename, nrows=5000) - 算真实内存:
df.memory_usage(deep=True).sum() / 1024**2得到 MB 数 - 按目标内存反推:
chunksize ≈ (目标内存 MB / 样本内存 MB) * 5000 - 特别注意长文本列、高基数分类列(如
user_agent),它们会让单块内存陡增 - 别照搬别人的经验值,你的数据分布才是关键参数
TextFileReader 对象误当 DataFrame 用,为什么 .shape 报错?
pd.read_csv(..., chunksize=N) 返回的是 TextFileReader,本质是迭代器,不是 DataFrame。
- 直接调
reader.shape→AttributeError -
next(reader).head()可以预览,但会消耗第一个 chunk,后续for chunk in reader从第二块开始 - 想预览又不破坏迭代:用
first_chunk = next(pd.read_csv(filename, chunksize=5000))单独处理 - 常见后果:逻辑跳过首块、统计漏数、聚合结果偏差
循环里累积 chunk 是最危险的内存陷阱
把每个 chunk .append() 进列表,或反复 pd.concat(),等于在内存里建一个持续膨胀的副本。
- 第 3–5 块后就容易触发
MemoryError,GC 来不及回收 - 正确做法:每块处理完立刻丢引用 —— 加
del chunk,大文件下建议显式gc.collect() - 流式写入:
chunk.to_csv('out.csv', mode='a', header=first_write),首次header=True,之后mode='a' - 流式入库:
chunk.to_sql('table', con, if_exists='append', index=False),确保con是 SQLAlchemy 引擎(带连接池) - 真要聚合:只保留标量结果,比如
sums.append(chunk['sales'].sum()),而不是存整个 chunk
dtype 和 usecols 不指定,就是在喂内存杀手
默认 object 类型和全列加载,是千万行数据内存爆炸的头号原因。
-
dtype={'user_id': 'category', 'score': 'float32', 'status': 'uint8'}:分类列省 70%+ 内存,float32直接减半 -
usecols=['id', 'amount', 'ts']:300 列日志里只用 3 列?不加这句照样全加载 -
memory_map=True对 GB 级文本有效,但查询速度可能降 30–50%,慎用于高频随机访问场景 - object 列一旦混入,pandas 就会为它单独分配一个 Block,每个单元格都是独立 Python 对象,缓存不友好
复杂点在于:内存优化不是单点动作,而是类型降级、分块策略、引用管理、IO 方式四者联动。最容易被忽略的是——你删了变量名,但没删引用;你设了 chunksize,但没算实际内存;你用了 category,却忘了 usecols 还在加载几百列无用字段。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











