astype("category")、categorical()与factorize()的区别及应用解析
Pandas分类变量转换方法对比:factorize()、Categorical()与astype("category")
Python里把变量转成分类变量有好几种方式,先看基础示例:
import numpy as np import pandas as pd mydata = pd.Series(['A', 'B', 'B', 'C']) # 原始数据 print(mydata) # 输出: # 0 A # 1 B # 2 B # 3 C # dtype: object # pd.factorize 输出包含编码数组和类别索引的元组 print(pd.factorize(mydata)) # 输出:(array([0, 1, 1, 2], dtype=int64), Index(['A', 'B', 'C'], dtype='object')) # pd.Categorical 生成分类对象 cat_obj = pd.Categorical(mydata) print(cat_obj) # 输出: # ['A', 'B', 'B', 'C'] # Categories (3, object): ['A', 'B', 'C'] # 提取类别:cat_obj.categories # astype('category') 将Series转为分类类型 cat_series = mydata.astype('category') print(cat_series) # 输出: # 0 A # 1 B # 2 B # 3 C # dtype: category # Categories (3, object): ['A', 'B', 'C'] # 提取类别:cat_series.cat.categories
一、三种方法的核心区别
- pd.factorize():本质是标签编码工具,返回整数编码数组+对应原始类别的索引元组。它不改变原数据类型,只是给每个唯一类别分配整数ID,更偏向于纯数值映射。
- pd.Categorical():生成独立的分类数据对象,是pandas专门的分类容器,但不属于Series/DataFrame结构,单独存储类别和对应数据。
- astype("category"):直接将原Series转为Categorical类型的Series,在原数据结构基础上修改类型,保留Series的所有操作方法。
二、优劣势对比
1. pd.factorize()
- 优势:
- 轻量快速,直接生成整数编码,适合模型需要纯数值输入的场景
- 支持任意可哈希类型,不局限于字符串类别
- 结果是元组,能直接提取编码和类别映射关系
- 劣势:
- 不保留分类数据的特殊属性(比如类别顺序、空类别),只是简单编码
- 生成的是普通数组,无法使用pandas分类类型的专属操作(如.cat下的方法)
2. pd.Categorical()
- 优势:
- 纯粹的分类容器,适合单独处理分类逻辑
- 可自定义类别顺序、提前指定未出现的类别(比如枚举所有可能的取值)
- 内存占用比原始object类型小,类别重复越多优势越明显
- 劣势:
- 不属于Series结构,无法直接和其他pandas数据无缝结合,需转成Series才能参与分析
- 操作不如astype转换后的分类Series直观
3. astype("category")
- 优势:
- 直接转换原Series,完全保留Series的所有操作(如.groupby()、.value_counts()),无缝融入日常分析流程
- 内存效率高,自带分类类型的所有特性(类别管理、顺序控制)
- 代码简洁直观,是日常数据清洗的首选
- 劣势:
- 无法直接获取整数编码,需额外调用
.cat.codes提取 - 默认基于当前数据的唯一值生成类别,自定义类别需额外传参
- 无法直接获取整数编码,需额外调用
三、适用场景选择
1. 决策树等模型输入
优先选pd.factorize():模型需要整数编码时,它一步返回整数数组,还能直接拿到类别映射方便后续解释模型;如果后续还要做特征工程,也可以先转成分类Series,再提取编码。
2. 生成频率表/统计分析
优先选astype("category"):转换后的分类Series可以直接用.value_counts()、.groupby()等方法,自动识别类别,包括自定义的未出现类别,统计更准确。
3. 提前定义固定类别(比如枚举值)
用**pd.Categorical()或astype("category")**加categories参数:
# 提前定义所有可能的类别,即使当前数据里没有 pd.Categorical(mydata, categories=['A', 'B', 'C', 'D']) mydata.astype('category', categories=['A', 'B', 'C', 'D'])
这种场景下pd.factorize()不适用,因为它只会基于当前数据生成类别。
四、后续类别修改的易用性
如果需要修改类别、添加新类别、更改值或合并类别,astype("category")生成的分类Series最易用,其次是pd.Categorical(),pd.factorize()几乎无法直接操作:
- 添加新类别:分类Series可以用
.cat.add_categories():cat_series = cat_series.cat.add_categories('D') - 合并类别:用
.cat.rename_categories()或.cat.set_categories():# 合并A和B为AB cat_series = cat_series.cat.rename_categories({'A':'AB', 'B':'AB'}) - 修改类别顺序:用
.cat.reorder_categories()
pd.Categorical()可以调用同样的.cat方法,但需要先转成Series才能方便结合其他数据;而pd.factorize()生成的是普通数组,修改类别只能重新编码,非常麻烦。
另外补充:sklearn的LabelEncoder、keras的to_categorical属于机器学习专用工具,适合在流水线中保存转换规则,方便后续对新数据做相同编码,而pandas的三种方法更偏向数据清洗和分析阶段的处理。
内容的提问来源于stack exchange,提问作者skan
相关产品推荐
相关产品推荐

