手动标签编码时Pandas测试集embarked列未编码问题求助
问题重现
你遇到的问题是:在循环编码训练集和测试集的分类变量时,测试集的embarked列仍然保留原始字符串标签,没有被编码为数字。原代码中错误地使用了df_train[col].unique()来获取编码的基准值,改为df[col].unique()后恢复正常。
核心原因拆解
问题出在数据类型的动态变化和匹配逻辑失效上,我们一步步拆解:
训练集先被修改,数据类型发生变化
当循环第一次处理df_train时,你用df_train[col].unique()获取原始字符串唯一值(比如['S','C','Q',nan]),然后把df_train里的这些字符串替换成了数字0、1、2。这时候df_train['embarked']的内容从字符串类型变成了数字+NaN的混合类型(数据类型会变为object或者float,取决于NaN的存在)。处理测试集时,匹配逻辑完全失效
当循环处理df_test时,你仍然调用df_train[col].unique(),但此时df_train['embarked']的唯一值已经是[0,1,2,nan](数字)。而df_test['embarked']还是原始的字符串['S','Q','C'],这时候执行df.loc[df[col] == uni , col] = n时,是字符串和数字做相等比较,结果全是False,没有任何行被匹配到,自然不会执行赋值操作,测试集的标签也就保留了原始状态。
为什么修改后能正常工作?
当你改成uniques = df[col].unique()时:
- 处理
df_train时,用的是训练集原始字符串唯一值,能正确匹配并替换为数字; - 处理
df_test时,用的是测试集原始字符串唯一值,同样是字符串和字符串比较,匹配逻辑有效,能把对应的字符串替换成数字。
额外提示:更规范的分类变量编码方式
其实你这种手动编码的方式容易出错,推荐用Pandas的Categorical类型或者LabelEncoder来处理,既能保证训练集和测试集编码一致,又更简洁:
from sklearn.preprocessing import LabelEncoder # 先在训练集上拟合编码器(排除NaN) le = LabelEncoder() le.fit(df_train['embarked'].dropna()) # 分别编码训练集和测试集,给NaN分配特殊值 df_train['embarked'] = df_train['embarked'].apply(lambda x: le.transform([x])[0] if pd.notna(x) else -1) df_test['embarked'] = df_test['embarked'].apply(lambda x: le.transform([x])[0] if pd.notna(x) else -1)
内容的提问来源于stack exchange,提问作者Marvin Taschenberger

