贝利信息

pandas 如何处理 category 类型列的内存优化与排序问题

日期:2026-01-24 00:00 / 作者:舞夢輝影
category类型能省内存,但仅适用于唯一值占比低于50%的低基数字符串列,如性别、省份等,可省60%–90%内存;高基数列反而增加开销。

category 类型真能省内存?先看它适合什么场景

能省,但不是所有字符串列都适合。关键看「唯一值数量 / 总行数」是否明显小于 0.5(即重复度高)。比如性别、省份、订单状态这类低基数(low-cardinality)列,转 category 后内存常减少 60%–90%;而用户昵称、日志消息这种几乎每行都不同的列,转了反而多一层索引开销。

用这行快速检查:

df['col'].nunique() / len(df)

别只看 df.info() 的 memory usage —— 它默认不 deep,得加 deep=True 才算真实字符串内存。

排序时 category 列为啥更快?但默认顺序可能不是你想要的

因为底层存的是整数编码(0, 1, 2…),排序实际是对整数数组操作,比逐个比较字符串快 3–5 倍。但注意:默认排序按「类别出现顺序」或「字典序」,不是你业务里的逻辑顺序(比如 “高” > “中” > “低”)。

读取阶段就优化,别等加载完再转

pd.read_csv() 把整列读成 object 再转 category,中间已占用大量内存。应该在读取时直接指定 dtype:

漏掉这步,100 万行含 3 个高重复字符串列的数据,可能多占 200MB+ 内存,且后续所有 groupbysort_values 都更慢。

容易被忽略的坑:category 列参与 merge 或 filter 时的行为
  • merge 时若左右 DataFrame 的 category 列 categories 不一致(比如左有 ['A','B'],右有 ['B','C']),结果列会自动转回 object,内存和性能优势瞬间消失
  • filter 时写 df[df['cat_col'] == 'X'] 没问题,但用 isin() 要小心:df[df['cat_col'].isin(['X','Y'])] 若 'Y' 不在 categories 中,会静默返回空 —— 不报错,但结果不对
  • 保存为 parquet 时默认保留 category 结构,但存 CSV 会变回字符串;重读 CSV 若没指定 dtype,又回到起点

真正省内存,靠的不是“转一次”,而是从读入、处理到输出全程保持类型意识。一个列转了 category,不代表它就永远安全了——任何隐式类型推断操作(比如 pd.concat()merge()、甚至某些 apply())都可能把它悄悄打回原形。