推荐采用dask dataframe进行惰性分块读取,它将文件切分为多个partition,仅在.compute()时按需加载,API与pandas高度兼容,支持usecols筛选列、dtype指定类型以节省内存和I/O。

直接用 pd.read_csv() 加载 500 万行以上 CSV 文件,大概率会出问题——不是内存爆掉,就是静默截断(比如只读了 100 万行),而且你根本收不到报错。这不是 pandas 的 bug,而是它默认设计就不面向“超大文件”场景。
为什么 pd.read_csv() 在超大文件上容易失败
常见现象包括:返回行数远少于实际、程序卡住无响应、MemoryError 或解析中途静默退出(尤其含未转义换行符、编码混乱、分隔符嵌套时)。根本原因在于:pd.read_csv() 是单次全量加载 + 同步解析,所有数据必须同时驻留内存,且底层 C 解析器在异常输入下可能直接放弃后续内容。
- 显式参数如
nrows=1_000_000或skiprows设置不当,会人为截断 - 未指定
encoding(如 UTF-8-BOM 文件漏掉encoding='utf-8-sig')导致解析提前终止 - 字段内含未转义换行符(例如 CSV 中的多行文本),会让解析器误判为新行
- 系统可用内存不足时,底层解析器可能不抛异常,而是悄悄停止读取
用 dask.dataframe 替代 pandas 做惰性读取
这是当前最实用、迁移成本最低的方案。Dask 不是“临时替代”,而是专为这类场景设计的工业级工具:它把文件逻辑切分成多个 partition,只在真正需要时才加载和计算,API 几乎和 pandas 一致。
- 安装只需:
pip install dask - 基础读取:
df = dd.read_csv('huge_file.csv')—— 此时没读任何数据,只是构建计算图 - 查看前几行:
df.head()(触发实际读取,安全) - 获取总行数:
df.shape[0].compute()(注意:.compute()才真正执行,结果必须能放进内存) - 务必加
usecols:比如dd.read_csv('f.csv', usecols=['id', 'timestamp', 'value']),可减少 30%+ I/O 和内存占用
用 chunksize 分块 + 向量化处理(适合简单聚合或流式写入)
如果你只需要做列运算、过滤、差分或追加写入,不用全局视图,chunksize 是轻量可靠的选择。关键是要彻底抛弃 iterrows() 和 apply()。
立即学习“Python免费学习笔记(深入)”;
- 错误示范:
for _, row in chunk.iterrows(): ...—— 百万行要跑几分钟 - 正确做法:所有计算都作用于整列,如
chunk['diff'] = chunk['col_a'] - chunk['col_b']、chunk['ratio'] = chunk['a'] / chunk['b'].replace(0, np.nan) - 差分要小心跨块边界:默认
.diff()只在块内有效;若需全局连续(如时间序列),得手动保存上一块末尾值并传入下一块 - 流式写入时控制表头:
to_csv(..., mode='a', header=first_chunk, index=False),避免重复表头
别忽略底层细节:编码、分隔符、数据类型
很多“读不出来”问题其实和规模无关,纯属格式配置失误。尤其是 Windows 生成的 CSV 或 Excel 导出文件,极易踩坑。
- 优先试
encoding='utf-8-sig',而不是'utf-8',能自动跳过 BOM 头 - 遇到解析错乱,先用
head -n 100 huge_file.csv | cat -A(Linux/macOS)或 PowerShell 的Get-Content huge_file.csv -Head 100 | Format-Hex查看真实分隔符和控制字符 - 指定
dtype能省大量内存:比如dtype={'user_id': 'category', 'score': 'float32'},比默认float64节省一半空间 - 对含千分位逗号的数字列(如
"1,234.56"),必须加thousands=','参数,否则全读成字符串
真正棘手的不是“怎么读”,而是“读完之后要不要全载入内存”。如果最终要调用 .compute() 或 pd.concat() 汇总,就得确认结果尺寸;如果只是抽样、统计、写回磁盘,那 chunk 或 dask 就已足够——这点常被忽略,结果在最后一步崩掉。


















