Python 3.10创建DataFrame分桶遇TypeError:无法设置Categorical新类别
问题:分桶AGE变量后执行ANOVA分析时触发Categorical类型错误
我有一个包含AGE和MEDV数值列的DataFrame,想把AGE分成3个分桶后做ANOVA分析,但执行代码时第一行就报错:
TypeError: Cannot setitem on a Categorical with a new category (Less than 35), set the categories first
尝试的代码如下:
df.loc[(df['AGE'] <= 35), 'age_group'] = 'Less than 35' df.loc[(df['AGE'] > 35)&(df["AGE"] < 70), 'age_group'] = '35 to 70' df.loc[(df['AGE'] > 70), 'age_group'] = 'Over 70' # Separate samples into a variable each a = df[df['age_group'] == "Less than 35"]["MEDV"] b = df[df['age_group'] == "35 to 70"]["MEDV"] c = df[df['age_group'] == "Over 70"]["MEDV"] f_statistic, p_value = stats.f_oneway(a, b, c) print("F_Statistic: {0}, P-Value: {1}".format(f_statistic,p_value))
使用Python 3.10的Jupyter Notebook,之前在其他环境用过类似代码正常运行,疑惑是遗漏步骤还是版本变更导致?
报错原因
这个错误和Python 3.10版本无关,核心问题是你要赋值的age_group列已经被定义为Categorical类型了。Categorical列的特点是只能使用预先定义好的类别值,直接赋值新的类别会触发这个错误。之前其他环境能运行,大概率是当时的age_group列是默认的object(字符串)类型,没有Categorical的限制。
解决方法
方法1:先初始化普通字符串列再赋值
先创建一个空的字符串列,避免Categorical的限制,赋值完成后可按需转为Categorical类型:
# 先创建普通字符串列 df['age_group'] = '' # 执行分桶赋值 df.loc[(df['AGE'] <= 35), 'age_group'] = 'Less than 35' df.loc[(df['AGE'] > 35)&(df["AGE"] < 70), 'age_group'] = '35 to 70' df.loc[(df['AGE'] > 70), 'age_group'] = 'Over 70' # 可选:转为有序Categorical类型,方便后续分析 df['age_group'] = pd.Categorical(df['age_group'], categories=['Less than 35', '35 to 70', 'Over 70'], ordered=True)
方法2:预先定义Categorical列的所有类别
如果需要一开始就用Categorical类型,先提前声明所有允许的类别:
# 先创建Categorical列并指定所有类别 df['age_group'] = pd.Categorical([], categories=['Less than 35', '35 to 70', 'Over 70'], ordered=True) # 再执行赋值 df.loc[(df['AGE'] <= 35), 'age_group'] = 'Less than 35' df.loc[(df['AGE'] > 35)&(df["AGE"] < 70), 'age_group'] = '35 to 70' df.loc[(df['AGE'] > 70), 'age_group'] = 'Over 70'
方法3:用pd.cut直接生成分桶列(推荐)
用pandas内置的pd.cut函数可以一步完成分桶,自动处理类别,避免手动赋值的麻烦:
import pandas as pd from scipy import stats # 定义分桶边界和标签 bins = [0, 35, 70, float('inf')] labels = ['Less than 35', '35 to 70', 'Over 70'] # 生成分桶列 df['age_group'] = pd.cut(df['AGE'], bins=bins, labels=labels, include_lowest=True) # 后续ANOVA代码不变 a = df[df['age_group'] == "Less than 35"]["MEDV"] b = df[df['age_group'] == "35 to 70"]["MEDV"] c = df[df['age_group'] == "Over 70"]["MEDV"] f_statistic, p_value = stats.f_oneway(a, b, c) print("F_Statistic: {0}, P-Value: {1}".format(f_statistic,p_value))
内容的提问来源于stack exchange,提问作者AJD
相关产品推荐
相关产品推荐

