category 能省内存是因为将重复值编码为整数索引,仅存储唯一值和对应 codes;低基数列(唯一值占比<5%)才适合转换,需注意避免退化操作和 categories 不一致问题。

为什么 category 能省内存?
因为 category 类型把重复的字符串(或其他值)转成整数编码,只存一份原始值(categories)和一列对应索引(codes)。比如 10 万行全是 "red"、"blue"、"green" 的列,用 object 类型每行都存一个字符串对象,而 category 只存 3 个字符串 + 10 万个 int8(默认)索引,内存直接降 5–10 倍。
怎么安全地转成 category?
不是所有列都适合转——只有低基数(unique 值少)、高重复率的列才值得转。盲目转换反而可能更占内存(比如唯一值超 10 万的列,categories 本身就很重)。
- 先用
df[col].nunique() / len(df)看下“唯一值占比”,低于 0.05(5%)通常值得转 - 用
df[col].astype("category")转换,但注意:它默认保留原始出现顺序,且不会自动丢弃未使用的分类(unused categories) - 如果后续会做
dropna()或过滤,建议加df[col].cat.remove_unused_categories()清理冗余分类 - 想控制编码类型(比如强制用
int8),得先设ordered=False再调cat.as_ordered()或直接用Categorical构造器
category 对常用操作的影响
多数聚合(groupby().size()、value_counts())能自动利用分类信息加速;但某些操作会悄悄退化回 object,比如 str.upper()、apply(lambda x: ...) —— 这时 codes 丢失,内存又涨回去。
- 字符串操作必须先转回
object:df[col].astype(str).str.upper() -
pd.concat()时若两个category列的categories不一致,结果列会变成object;统一用CategoricalDtype预定义可避免 - 写入 Parquet 时,默认保留
category,但 CSV 会还原为字符串——别指望 CSV 能省空间
一键压缩内存的实用函数
手动逐列判断太慢,可以用这个轻量函数扫描并转换:
df.memory_usage(deep=True).sum()
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











