chunksize参数使pandas.read_csv()返回TextFileReader迭代器而非DataFrame,需循环处理每个chunk;错误直接调用.head()会报错,且累积concat易致内存爆炸,应优先用usecols和dtype优化单chunk内存占用。

chunksize参数本质是返回迭代器,不是直接读入内存
设置 chunksize 后,pandas.read_csv() 不再返回 DataFrame,而是返回一个 TextFileReader 对象——它是个可迭代器,每次 next() 或用 for 循环取一个 chunk,每个 chunk 才是真正的 DataFrame。很多人误以为设了 chunksize 就“自动分批处理”,结果直接对返回对象调用 .head() 报错:AttributeError: 'TextFileReader' object has no attribute 'head'。
正确做法是显式循环或手动取 chunk:
reader = pd.read_csv("big_file.csv", chunksize=10000)
for chunk in reader:
# 对每个 chunk 做处理,比如过滤、聚合
processed = chunk[chunk["value"] > 100]
# 注意:这里不能直接 .append() 到列表再 concat——可能爆内存
chunksize大小选多少才不崩也不慢
没有固定最优值,取决于你的行宽(列数+字符串长度)、可用内存、以及后续操作类型。太小(如 chunksize=100)会导致 I/O 次数爆炸,CPU 大量花在文件读取和对象创建上;太大(如 chunksize=500000)可能单个 chunk 就占满内存,触发 MemoryError。
- 起步建议从
chunksize=10000开始,在监控内存(psutil.Process().memory_info().rss)下逐步调大 - 如果文件含大量长文本列,chunksize 要比纯数值文件更保守(比如降为 5000)
- 若后续要做
groupby().agg(),最好确保同一组数据不出现在多个 chunk 中——这时 chunksize 不是关键,得配合iterator=True+ 手动按 key 分块读取,或改用dask.dataframe
常见错误:在 chunk 循环里无节制地累积结果
最典型陷阱是这样写:
立即学习“Python免费学习笔记(深入)”;
all_data = []
for chunk in pd.read_csv("log.csv", chunksize=5000):
all_data.append(chunk[chunk["status"] == 200])
result = pd.concat(all_data) # ❌ 内存翻倍甚至三倍
问题在于:每个 chunk 是新 DataFrame,append 到列表只是引用+复制元数据,但 pd.concat() 会一次性把所有 chunk 拼成一个大对象——完全抵消 chunk 的意义。
替代方案取决于目标:
- 如果只是统计(如总请求数、平均响应时间),用变量累加:
total_count += len(chunk)、sum_time += chunk["time"].sum() - 如果必须保留筛选后数据,且总量可控,用
pd.concat()但限制最终规模(比如只保留前 10 万条) - 如果要写回文件,直接每个 chunk 处理完就
to_csv(..., mode="a", header=False)追加,避免中间存储
别忽略 dtype 和 usecols——它们比 chunksize 更早省内存
chunksize 是“怎么分”,而 dtype 和 usecols 是“读什么、怎么存”。这两者在 chunk 之前就起效,收益更高:
-
usecols=["id", "amount", "ts"]:跳过不需要的列(比如日志里的原始 JSON 字段),I/O 和内存直接下降 30%~70% -
dtype={"id": "uint32", "amount": "float32"}:避免 pandas 默认用int64/float64,单列就能省一半内存 - 对日期列务必用
parse_dates=["ts"],否则读成 object 类型,后续转 datetime 会额外吃内存且极慢
真正的大文件处理,chunksize 往往是最后一步调节手段;先靠 usecols 和 dtype 把单个 chunk 的体积压下来,才能让 chunksize 设得更大、更稳。


















