如何高效利用pandas分块读取处理10GB CSV文件,Python实现?
- 内容介绍
- 文章标签
- 相关推荐
本文共计939个文字,预计阅读时间需要4分钟。
读取10GB+的CSV文件时,直接使用`pandas.read_csv()`默认将整个文件加载进内存,可能导致内存消耗迅速上升至20GB以上,进而引发系统OOM错误或卡死。为避免这种情况,可以采用以下方法:
根本原因不是pandas慢,而是它默认的「全量加载 + 类型自动推断」策略在大文件上完全不适用——类型推断需要扫描全部数据,而内存里存不下。
- 避免使用
dtype='category'或infer_datetime_format=True等加重推断负担的参数 - 显式指定
dtype(比如把所有数字列设为'float32'而非默认'float64')能减少30%~50%内存占用 - 禁用索引:
index_col=False,除非你真要用某列当索引
分块读取的核心参数怎么设才不翻车
chunksize 不是越大越好,也不是越小越稳。设成 50000 行(约 5–8MB 内存/块)是多数场景的甜点值:太小会导致I/O次数过多、Python循环开销占比上升;太大仍可能单块爆内存,尤其字段含长文本时。
关键是要配合 usecols 和 dtype 一起用,否则分块没意义——光读100列中的5列,但每块还是按100列解析,内存照样涨。
立即学习“Python免费学习笔记(深入)”;
-
usecols=['user_id', 'event_time', 'action']—— 只加载需要的列,跳过无关字段 -
dtype={'user_id': 'uint32', 'action': 'category'}—— 显式声明类型,跳过推断 -
parse_dates=['event_time']放在分块内做,别等全读完再转;如果时间格式统一,可用date_parser提前编译解析器
分块处理后如何安全聚合或写回磁盘
别在内存里 accumulate 所有 chunk 的 DataFrame,那是回到原点。聚合类任务(如求和、计数、分组均值)应逐块更新中间状态;写入类任务优先用 to_csv(..., mode='a', header=False) 追加,而不是拼完再写。
例如统计每类 action 出现次数:
counts = {} for chunk in pd.read_csv('big.csv', chunksize=50000, usecols=['action'], dtype={'action': 'category'}): chunk_counts = chunk['action'].value_counts() for act, cnt in chunk_counts.items(): counts[act] = counts.get(act, 0) + cnt
写入新CSV时注意:header 只在第一块写一次,后续必须关掉;若需压缩,直接用 compression='gzip',别用 pd.concat().to_csv() 中间落地临时文件。
比 read_csv 分块更省内存的替代方案
当你的操作足够简单(比如过滤、抽样、字段转换),csv 标准库 + 生成器比 pandas 更轻。10GB 文件下,纯 Python 逐行读+条件判断,内存稳定在 10–20MB;pandas 分块最低也要 100MB+ 起步。
示例:提取所有 action == 'click' 的行并写入新文件
import csv with open('big.csv') as fin, open('clicks.csv', 'w', newline='') as fout: reader = csv.DictReader(fin) writer = csv.DictWriter(fout, fieldnames=reader.fieldnames) writer.writeheader() for row in reader: if row['action'] == 'click': writer.writerow(row)
这招对「单条件过滤」「字段映射」「行级清洗」极快且可控;但一旦涉及跨行逻辑(如窗口计算)、缺失值插补、多列关联,就得切回 pandas 分块——别硬扛。
真正棘手的永远不是“怎么读”,而是“读进来之后不做全量 merge / pivot / join,还能不能完成业务目标”。先想清楚你要的输出粒度,再决定 chunksize 和处理边界。
本文共计939个文字,预计阅读时间需要4分钟。
读取10GB+的CSV文件时,直接使用`pandas.read_csv()`默认将整个文件加载进内存,可能导致内存消耗迅速上升至20GB以上,进而引发系统OOM错误或卡死。为避免这种情况,可以采用以下方法:
根本原因不是pandas慢,而是它默认的「全量加载 + 类型自动推断」策略在大文件上完全不适用——类型推断需要扫描全部数据,而内存里存不下。
- 避免使用
dtype='category'或infer_datetime_format=True等加重推断负担的参数 - 显式指定
dtype(比如把所有数字列设为'float32'而非默认'float64')能减少30%~50%内存占用 - 禁用索引:
index_col=False,除非你真要用某列当索引
分块读取的核心参数怎么设才不翻车
chunksize 不是越大越好,也不是越小越稳。设成 50000 行(约 5–8MB 内存/块)是多数场景的甜点值:太小会导致I/O次数过多、Python循环开销占比上升;太大仍可能单块爆内存,尤其字段含长文本时。
关键是要配合 usecols 和 dtype 一起用,否则分块没意义——光读100列中的5列,但每块还是按100列解析,内存照样涨。
立即学习“Python免费学习笔记(深入)”;
-
usecols=['user_id', 'event_time', 'action']—— 只加载需要的列,跳过无关字段 -
dtype={'user_id': 'uint32', 'action': 'category'}—— 显式声明类型,跳过推断 -
parse_dates=['event_time']放在分块内做,别等全读完再转;如果时间格式统一,可用date_parser提前编译解析器
分块处理后如何安全聚合或写回磁盘
别在内存里 accumulate 所有 chunk 的 DataFrame,那是回到原点。聚合类任务(如求和、计数、分组均值)应逐块更新中间状态;写入类任务优先用 to_csv(..., mode='a', header=False) 追加,而不是拼完再写。
例如统计每类 action 出现次数:
counts = {} for chunk in pd.read_csv('big.csv', chunksize=50000, usecols=['action'], dtype={'action': 'category'}): chunk_counts = chunk['action'].value_counts() for act, cnt in chunk_counts.items(): counts[act] = counts.get(act, 0) + cnt
写入新CSV时注意:header 只在第一块写一次,后续必须关掉;若需压缩,直接用 compression='gzip',别用 pd.concat().to_csv() 中间落地临时文件。
比 read_csv 分块更省内存的替代方案
当你的操作足够简单(比如过滤、抽样、字段转换),csv 标准库 + 生成器比 pandas 更轻。10GB 文件下,纯 Python 逐行读+条件判断,内存稳定在 10–20MB;pandas 分块最低也要 100MB+ 起步。
示例:提取所有 action == 'click' 的行并写入新文件
import csv with open('big.csv') as fin, open('clicks.csv', 'w', newline='') as fout: reader = csv.DictReader(fin) writer = csv.DictWriter(fout, fieldnames=reader.fieldnames) writer.writeheader() for row in reader: if row['action'] == 'click': writer.writerow(row)
这招对「单条件过滤」「字段映射」「行级清洗」极快且可控;但一旦涉及跨行逻辑(如窗口计算)、缺失值插补、多列关联,就得切回 pandas 分块——别硬扛。
真正棘手的永远不是“怎么读”,而是“读进来之后不做全量 merge / pivot / join,还能不能完成业务目标”。先想清楚你要的输出粒度,再决定 chunksize 和处理边界。

