内存从16gb压到8gb靠三件事:读数据时锁死dtype、字符串转category、用chunksize流式处理;其他技巧均为其延伸或补救。

直接结论:内存从16GB压到8GB不是靠换机器,而是靠三件事——读数据时就锁死dtype、把重复字符串转成category、用chunksize流式处理。其他所有技巧,都是这三件事的延伸或补救。
读CSV时必须显式指定dtype和usecols
默认情况下pd.read_csv()会把所有列当object类型读进来,每个字符串值都带Python对象头开销,1000万行可能多占5–6GB。更糟的是,它会扫全文件推断类型,慢且不准。
- 先用小样本定类型:
pd.read_csv("data.csv", nrows=10000).dtypes,把结果存成字典传给dtype参数 - 数值列能降就降:
'user_id': 'uint32'比'int64'省内存一半;空值多的整数列用'Int64'(首字母大写)保留缺失语义 - 绝对不要省
usecols:193列的文件只用其中5列?加usecols=['id', 'status', 'amount', 'ts', 'region'],加载速度直接快2–3倍,内存少占70%+ - 时间列必须
parse_dates:否则会被当字符串存,object类型开销爆炸
字符串列优先转category,别信自动优化
astype('category')不是锦上添花,是救命稻草。一个含10万唯一值的字符串列,转category后内存可能从1.2GB降到80MB——因为内部只存一份值表+一串整数索引。
- 高重复率才值得转:城市名、状态码、产品类目这类字段,重复率通常>90%,转完立竿见影
- 低重复率慎用:比如用户生成的长评论、日志消息,唯一值接近行数,转
category反而更费内存 - 别在
groupby前才转:先转再分组,groupby速度能快5–20x;如果边groupby边转,Pandas会在每块里重复建category表 - 合并多个DataFrame时,确保
category的categories一致,否则concat会静默升为object
chunksize不是越大越好,得算单行内存再设
设chunksize=100000看起来很“大气”,但若单行平均占120KB,一块就吃掉12GB内存,还没开始处理就OOM。
- 估算单行内存:
df.memory_usage(deep=True).sum() / len(df),用前1000行快速测 - 保守起步:
chunksize = int(可用内存字节数 * 0.7 / 单行字节数),比如1GB空闲内存、单行80KB,起始设10000,跑通再试15000 - 千万别
pd.concat([chunk for chunk in pd.read_csv(..., chunksize=...)]):这等于把所有块全加载进内存,白用了chunksize - 要聚合就边读边算:每块内
chunk.groupby('cat')['val'].sum(),最后pd.concat局部结果再.groupby().sum()收口
最常被忽略的一点:类型转换不是一次性动作。当你对千万行做df['col'] = df['col'].astype('category'),Pandas会先复制整列再替换,峰值内存可能翻倍。真正安全的做法,是在read_csv里用converters或dtype一步到位,或者用inplace=True配合del手动清理中间引用。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











