OOM几乎从来不是pandas本身的问题,而是pd.read_csv()默认全量加载、类型推断和object列滥用导致内存暴涨2–4倍;优化核心是读时控制(chunksize/usecols/dtype/index_col)、读入降级(数值downcast/字符串转category)、计算不累积(groupby.size优于value_counts)。

直接说结论:OOM 几乎从来不是 pandas 本身的问题,而是 pd.read_csv() 默认全量加载 + 类型推断 + object 列滥用导致内存暴涨 2–4 倍。优化核心就三件事:读的时候就控住、读进来就降级、算的时候不累积。
pd.read_csv() 加载大文件必设的四个参数
不加任何参数直接读 GB 级 CSV,等于主动申请 OOM。关键不是“能不能读”,而是“要不要把整张表塞进内存再开始干活”。
-
chunksize:设为50000或100000,返回TextFileReader迭代器,一块一块处理,峰值内存可控 -
usecols:只读真正需要的列,比如统计销量,就别碰'user_address'、'remark'这类字段 -
dtype:显式指定类型,避免 pandas 自动推成object或float64;重复字符串列优先用'category',整数列能用np.int32就不用int64 -
index_col=False:除非真要用索引做merge或groupby,否则关掉自动索引构建,省下额外内存和时间
df.memory_usage(deep=True) 才是真实内存用量
df.info() 默认显示的是浅层估算值,对 object 列严重低估——它只算指针大小(8 字节),不递归算每个字符串实际占多少。真正要诊断,必须加 deep=True:
df.memory_usage(deep=True).sum() # 返回字节数 df.memory_usage(deep=True).sum() / (1024**3) # 转 GB,才可信
常见错误现象:sys.getsizeof(df) 返回值比 df.memory_usage(deep=True).sum() 小一个数量级,因为它完全忽略底层 NumPy 数组和字符串对象的实际内存;df.info() 显示 “memory usage: 300.0 MB”,但任务管理器里 Python 进程已吃掉 1.2 GB —— 那多出来的就是 object 列里藏着的字符串本体。
立即学习“Python免费学习笔记(深入)”;
数值列降级和字符串转 category 的实操边界
不是所有列都适合无脑降级或转 category,踩错会丢数据或变慢。
- 数值列用
pd.to_numeric(..., downcast='integer')或downcast='float'是安全的,但得确认范围:int32最大支持2147483647,超了会静默溢出成负数 - 字符串列转
category有效当且仅当唯一值数量 ≪ 总行数(比如 100 万行中只有 12 个省份);若唯一值 > 行数 50%,反而比object更占内存,因为多了编码映射表 -
convert_dtypes()看似智能,但它对字符串列默认转成string(Pandas 新 dtype),不解决内存问题,也不压缩;真想省内存,还是得手动.astype('category')
groupby().size() 比 value_counts() 更抗 OOM
单列频次统计时,df[col].value_counts() 会先构造完整 Series 再去重计数,中间对象无法流式释放;而 df.groupby(col).size() 可配合 chunksize 分块累加,内存只随唯一值数量线性增长。
- 分块统计示例:
counts = pd.Series(dtype='uint32') for chunk in pd.read_csv('log.csv', chunksize=50000, usecols=['ip'], dtype={'ip': 'category'}): counts = counts.add(chunk['ip'].value_counts(), fill_value=0) # 最后 counts 就是全局频次 - 慎用
pd.concat([chunk.value_counts() for chunk in reader]):每 concat 一次就拷贝一次,N 块 → N 次内存峰值 - 如果连单块
value_counts()都撑不住(比如百亿级 ID),就得落地哈希分桶:用hashlib.md5(key.encode()).hexdigest()[:2]取前两位做文件名,写到tmp_00.csv~tmp_ff.csv,再分别聚合
最易被忽略的一点:dtype 不一致会导致 concat 或 groupby 隐式升格——比如 int32 列和 int64 列拼一起,结果全是 int64,悄悄多吃一倍内存。处理前务必统一 dtypes。


















