应仅对“低基数高重复”的列使用pd.categorical,即nunique()/len(df)远小于1(如

用 pd.Categorical 能把字符串分类列的内存降到原来的 1/5 甚至更低,但前提是列里重复值多、类别数远小于行数——否则反而更占内存。
什么时候该用 pd.Categorical?
它不是万能压缩器,只对“低基数高重复”的列有效。比如城市名、状态码、产品类型这类字段;对用户ID、订单号、时间戳这种几乎每行都不同的列,转成 Categorical 反而增加内存开销(因为额外存了 categories 数组 + codes 整数数组)。
- 判断依据:运行
df[col].nunique() / len(df),结果 - 典型场景:CSV 读入后立刻处理,或 groupby 前优化分组键
- 注意:
pd.Categorical不会自动排序 categories,顺序取决于首次出现顺序,影响后续sort_values()
怎么安全地转换并验证效果?
别直接 df[col] = df[col].astype('category') 就完事。得先看原始 dtype 和内存占用,再对比转换后变化。
- 查当前内存:用
df[col].memory_usage(deep=True)(deep=True才算字符串实际字节) - 转换推荐写法:
df[col] = pd.Categorical(df[col]),比.astype('category')更明确,且可传categories=...或ordered=True - 验证是否真省内存:再跑一次
df[col].memory_usage(deep=True),同时检查df[col].dtype确实是CategoricalDtype
转成 Categorical 后哪些操作会变慢或出错?
它牺牲了部分灵活性来换空间,很多看似常规的操作会隐式触发“展开”(即转回 object),导致内存暴涨、速度骤降。
-
df[col].str.contains(...)会报 AttributeError —— Categorical 没.str访问器,得先df[col].astype(str).str.contains(...) -
df[col] += '_suffix'不支持原地拼接,必须显式转回 string:df[col].astype(str) + '_suffix' - 与非 categorical 列做
==比较时,Pandas 会尝试对齐 categories,若两边 category 不一致,可能返回全 False 或抛TypeError
最常被忽略的一点:Categorical 的 categories 是全局共享的,如果对一个 Series 做 .cat.remove_unused_categories() 或 .cat.set_categories(),只影响该 Series,不会同步到其他同名列——这点在 merge 或 concat 后尤其容易踩坑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











