用 dtypes 精确控制每列数据类型可显著降低内存占用:整数列按需转 int8/int16/int32,浮点列优先 float32,字符串列取值有限时转 category,读取时通过 dtype、usecols、chunksize 参数优化,并注意空值处理与及时清理无用类别。

用 dtypes 精确控制每列数据类型
默认情况下,Pandas 会把整数列读成 int64、浮点列读成 float64,哪怕数据本身只用 int8 就够了。对千万行以上的 DataFrame,这种“过度分配”会让内存翻几倍。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先用
df.dtypes查看当前类型,再用df.memory_usage(deep=True).sum()看总占用 - 整数列:检查是否含负数和范围,能转
int8/int16/int32就别留int64 - 浮点列:若精度允许(比如温度保留 1 位小数),可转
float32;注意float16在 Pandas 中不支持所有运算,慎用 - 字符串列:优先转
category类型(尤其取值有限的字段,如国家、状态、产品类别);但若唯一值太多(>50% 行数),category反而更占内存
读取时就做内存优化:pd.read_csv() 的关键参数
等数据全读进内存再压缩,已经晚了。真正省内存的时机是加载阶段。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
dtype参数直接指定每列类型,例如:dtype={'user_id': 'uint32', 'status': 'category'} - 用
usecols只读需要的列,避免加载冗余字段 - 用
chunksize分块读取+处理,适合无法一次性装入内存的场景;注意pd.concat(chunks)会临时加倍内存,建议边读边存到磁盘或数据库 - 数值列含空值时,
int64无法存NaN,Pandas 会自动升为float64—— 若必须保留整型空值,改用Int64(首字母大写的可空整型,Pandas 专用)
释放未使用的内存:别只靠 del 和 gc.collect()
del df 只是删引用,不等于立刻释放内存;gc.collect() 对大型 NumPy 数组效果也很有限,因为底层内存由 NumPy 自己管理。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 对已处理完的中间 DataFrame,调用
df._mgr.blocks或直接df = None,并确认无其他变量引用它 - 更可靠的做法是用
df.copy(deep=False)创建视图后尽快丢弃原对象;或用df.astype(..., copy=False)避免复制 - 如果用了
category类型,记得定期调用df[col].cat.remove_unused_categories()清理未出现的类别,否则类别列表会一直膨胀
替代方案:当 Pandas 真撑不住时考虑 polars 或 dask
不是所有大数据问题都该硬扛。10GB+ 的 CSV,或需频繁 groupby + join 的场景,Pandas 的单线程 + 内存拷贝模型天然受限。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
polars在多数聚合/过滤操作上比 Pandas 快 2–5 倍,内存常低 30%–50%,API 类似,迁移成本低;但生态插件少,绘图/统计建模需转回 Pandas -
dask.dataframe适合超大文件分片计算,但调度开销明显,小数据反而更慢;写法接近 Pandas,但执行是惰性的,别忘了.compute() - 临时救急:用
pd.to_feather()保存为二进制格式,下次读取快且内存占用更低(相比 CSV / pickle);注意 Feather 不跨语言完全兼容,别用它做长期归档
内存优化不是一锤子买卖。同一份数据,在不同操作链路中,最省内存的表示方式可能完全不同——比如 groupby 前用 category,但 merge 后因索引对齐又得转回 object。得随时用 memory_usage 验证,而不是依赖某次“优化”就一劳永逸。


















