You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas:对行子集的category列使用apply方法时出现异常的咨询

Pandas中Category类型列子集apply触发未存在类别KeyError的问题

问题重现

当你将DataFrame的列转为Category类型后,取行子集并使用apply通过字典映射值时,会触发子集中不存在的类别KeyError,即使子集中根本没有该类别值:

df = pd.DataFrame({'A':[11,22,33], 'B':['foo','baz', 'bar']})
df['B'] = df['B'].astype('category')
dfs = df[df['A'] > 20].reset_index(drop=True)
d = {'baz': 14, 'bar': 19}
dfs['B'].apply(lambda x: d[x])

执行后会报错:KeyError: 'foo',但dfs中明明只有baz和bar两个值。而如果不将列转为Category类型,代码可以正常运行并得到预期结果:

df = pd.DataFrame({'A':[11,22,33], 'B':['foo','baz', 'bar']})
dfs = df[df['A'] > 20].reset_index(drop=True)
d = {'baz': 14, 'bar': 19}
dfs['B'].apply(lambda x: d[x])

输出:

0    14
1    19
Name: B, dtype: int64

原因分析

Category类型的列会保留原始DataFrame的所有类别元数据,即使生成子集后某些类别并没有出现在子集中。当使用apply方法时,Pandas内部会基于这些完整的类别集合进行操作(而非仅子集里的实际值),导致lambda函数被应用到所有原始类别,包括子集中不存在的foo,从而触发KeyError。

解决方案

方案1:移除子集中未使用的类别

在生成子集后,调用cat.remove_unused_categories()删除未被使用的类别,这样apply就只会处理子集中实际存在的类别:

df = pd.DataFrame({'A':[11,22,33], 'B':['foo','baz', 'bar']})
df['B'] = df['B'].astype('category')
dfs = df[df['A'] > 20].reset_index(drop=True)
# 清理未使用的类别
dfs['B'] = dfs['B'].cat.remove_unused_categories()
d = {'baz': 14, 'bar': 19}
dfs['B'].apply(lambda x: d[x])

方案2:改用map方法(推荐)

map方法专门用于元素级别的映射,只会处理子集中实际存在的值,不受Category列的完整类别元数据影响:

df = pd.DataFrame({'A':[11,22,33], 'B':['foo','baz', 'bar']})
df['B'] = df['B'].astype('category')
dfs = df[df['A'] > 20].reset_index(drop=True)
d = {'baz': 14, 'bar': 19}
dfs['B'].map(d)

方案3:将Category列转回字符串类型

如果不需要保留Category类型,可以先将列转回普通字符串,再使用apply:

df = pd.DataFrame({'A':[11,22,33], 'B':['foo','baz', 'bar']})
df['B'] = df['B'].astype('category')
dfs = df[df['A'] > 20].reset_index(drop=True)
d = {'baz': 14, 'bar': 19}
dfs['B'].astype(str).apply(lambda x: d[x])

内容的提问来源于stack exchange,提问作者javadr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:07:44