chunksize需结合实际内存占用计算,不能仅设行数;TextFileReader是迭代器,不可直接调用DataFrame方法;必须指定dtype和usecols,并避免累积chunk。

chunksize不是设了就省内存,得先算单块实际占用
直接写 chunksize=10000 很可能无效——它只控制行数,不控制内存。一行含 200 字符的 object 列,比 10 行全 int32 还吃内存。正确做法是先试读一小段,再反推:
- 用
pd.read_csv(filename, nrows=5000)读前 5000 行 - 运行
df.memory_usage(deep=True).sum() / 1024**2算出 MB 数 - 若占 120MB,目标内存 500MB,则合理
chunksize ≈ 500 / 120 * 5000 ≈ 20000
尤其注意长文本、高基数分类列(如日志中的 user_agent),它们会让单块暴涨。别信“别人用 10 万行没问题”,你的数据分布才是关键。
TextFileReader 不是 DataFrame,别直接调 .shape 或 .head()
pd.read_csv(..., chunksize=N) 返回的是 TextFileReader 对象,本质是迭代器。常见错误:
-
reader = pd.read_csv('x.csv', chunksize=5000); print(reader.shape)→AttributeError -
next(reader).head()可以,但会消耗第一个 chunk,后续for chunk in reader就从第二块开始 - 想预览又不破坏迭代?用
first_chunk = next(pd.read_csv('x.csv', chunksize=5000)),然后单独处理它
误当 DataFrame 用,轻则报错,重则逻辑跳过首块数据,结果漏统计。
立即学习“Python免费学习笔记(深入)”;
循环里别攒 chunk,处理完立刻丢引用
最常踩的坑:把每个 chunk .append() 进列表,或反复 pd.concat() 累积。这等于在内存里建了个越来越大的副本,GC 来不及回收,第 3–5 块后就 MemoryError。
- 流式写 CSV:
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 - 加
del chunk和gc.collect()(大文件下建议显式加)
chunk 是实打实的 DataFrame,不是指针。留着变量名,Python 就不会释放它。
dtype 和 usecols 不是可选项,是必填项
默认 object 类型和全列加载,是内存杀手。不指定 dtype,pandas 会把整数当 int64、字符串全塞进 Python object;不加 usecols,300 列日志里你只用 3 列,却仍加载全部。
-
dtype={'user_id': 'category', 'score': 'float32', 'status': 'uint8'}—— 分类列省 70%+ 内存,float32直接减半 -
usecols=['user_id', 'event_time', 'action']—— 减少 I/O 和解析开销,尤其对 Excel 更明显 - 含大量 NaN 的稀疏列?加
sparse=True(需 pandas ≥ 1.4)或改用pd.arrays.SparseArray - UTF-8 文件别依赖默认编码,显式写
encoding='utf-8',避开UTF-8-sig的 BOM 解析开销
这些不是“优化技巧”,是处理超大文件时的启动配置。漏掉任意一项,都可能让 chunksize 的努力白费。


















