本节介绍分类数据的常用操作:类别重命名、增删、排序、重编码、切片与合并等。
1. 重命名类别:rename_categories()
s = pd.Series(['a', 'b', 'a']).astype('category')
s.cat.rename_categories(['X', 'Y'])
# 0 X
# 1 Y
# 2 X
# Categories (2, object): ['X', 'Y']使用字典映射(只重命名部分):
s.cat.rename_categories({'a': 'alpha', 'b': 'beta'})
# 0 alpha
# 1 beta
# 2 alpha注意
重命名后编码不变,只改变显示内容。新类别数量必须与原一致(除非是字典映射)。
2. 重排序:reorder_categories()
s = pd.Series(['高', '低', '中']).astype('category')
print(s.cat.categories) # Index(['低', '高', '中'])
s_reordered = s.cat.reorder_categories(['低', '中', '高'])
print(s_reordered.cat.categories) # Index(['低', '中', '高'])
print(s_reordered.cat.ordered) # False(重排序不自动设置有序)重排序只改变类别顺序,不改变数据本身编码。若需要比较顺序,还需
as_ordered()。
3. 添加类别:add_categories()
s = pd.Series(['a', 'b']).astype('category')
s.cat.add_categories(['c', 'd'])
# Categories (4, object): ['a', 'b', 'c', 'd']用途
当数据可能在未来出现新类别时,先添加类别可以保证结构一致。
4. 移除类别:remove_categories()
s = pd.Series(['a', 'b', 'c']).astype('category')
s.cat.remove_categories('c')
# 0 a
# 1 b
# 2 NaN ← 'c' 被转为缺失
# Categories (2, object): ['a', 'b']注意
移除类别不会删除数据中已有的值,而是将对应值变为
NaN。这与dropna不同。
5. 设置类别全集:set_categories()
set_categories() 可以同时添加、移除类别,并可设置是否有序。
s = pd.Series(['a', 'b', 'c']).astype('category')
s.cat.set_categories(['a', 'b', 'c', 'd'], ordered=True)
# Categories (4, object): ['a' < 'b' < 'c' < 'd']
# 移除类别时,数据中对应的值转为 NaN
s.cat.set_categories(['a', 'b'])
# 0 a
# 1 b
# 2 NaN参数
| 参数 | 说明 |
|---|---|
new_categories | 新类别列表 |
ordered | 是否有序(默认保持原状态) |
rename | 如果为 True,则重命名而不是重新映射 |
set_categories vs add/remove
add_categories只能增加remove_categories只能删除set_categories可任意组合设置全集
6. 有序与无序转换
as_ordered()
将无序分类转为有序(需类别本身有顺序语义):
s = pd.Series(['低', '高', '中']).astype('category')
s.cat.as_ordered()
# Categories (3, object): ['低' < '中' < '高']as_unordered()
s.cat.as_unordered()
# Categories (3, object): ['低', '中', '高']有序分类的比较
- 有序分类支持
<、<=、>、>=- 无序分类只支持
==和!=
7. 移除未使用类别:remove_unused_categories()
s = pd.Series(['a', 'b', 'a']).astype(
pd.CategoricalDtype(categories=['a', 'b', 'c'])
)
print(s.cat.categories) # Index(['a', 'b', 'c'])
s_clean = s.cat.remove_unused_categories()
print(s_clean.cat.categories) # Index(['a', 'b'])意义
保留大量未使用的类别会浪费内存与排序时间,清洗后更高效。
8. 排序与比较
有序分类排序
s = pd.Series(['中', '低', '高']).astype(
pd.CategoricalDtype(categories=['低', '中', '高'], ordered=True)
)
s.sort_values()
# 1 低
# 0 中
# 2 高比较运算
s > '中'
# 0 False
# 1 True
# 2 False数值比较(无顺序时报错)
s_unordered = s.cat.as_unordered()
# s_unordered > '中' # TypeError9. 与字符串方法结合
分类数据可以直接使用 .str 访问器:
s = pd.Series(['apple', 'banana']).astype('category')
s.str.upper()
# 0 APPLE
# 1 BANANA
# dtype: object ← 返回 object,不再保留 category但注意:.str 返回的是普通字符串 Series,分类信息丢失。
10. 合并与连接
concat
s1 = pd.Series(['a', 'b']).astype('category')
s2 = pd.Series(['c', 'a']).astype('category')
pd.concat([s1, s2])
# 0 a
# 1 b
# 2 c
# 3 a
# dtype: category若两个分类类型一致,则结果仍为 category;若不一致,则退化为 object。
merge
df1 = pd.DataFrame({'id': [1, 2], 'cat': ['a', 'b']})
df2 = pd.DataFrame({'id': [2, 3], 'cat': ['b', 'c']})
df1['cat'] = df1['cat'].astype('category')
df2['cat'] = df2['cat'].astype('category')
merged = df1.merge(df2, on='id')
print(merged['cat_x'].dtype) # object(因为两列类别不同,合并后可能退化)11. 与缺失值处理
s = pd.Series(['a', None, 'b']).astype('category')
# 丢弃缺失
s.dropna()
# 填充缺失(注意填充值必须属于类别,否则报错)
s.fillna('a')
# 添加新类别再填充
s.cat.add_categories('unknown').fillna('unknown')fillna 限制
分类数据的
fillna填充值必须是已有类别,否则需要先add_categories。
小结
rename_categories重命名reorder_categories重排序add_categories/remove_categories/set_categories增删/设置as_ordered/as_unordered切换顺序remove_unused_categories清理未用类别- 合并后可能退化为 object,需注意