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

Pandas:如何处理测试集中训练集未观测到的分类特征

处理测试集出现训练集未观测分类特征的解决方案

我来给你梳理几个靠谱的方法,解决你遇到的「测试集出现训练集没见过的分类特征,导致独热编码后特征不匹配」的问题,结合你的例子一步步说:

首先回顾下你的场景:训练集是这个DataFrame

import pandas as pd
old = pd.DataFrame({"car":["Audi", "BMW", "Mazda"]})

用pd.get_dummies(old)编码后,得到car_Audi、car_BMW、car_Mazda三个特征列。但如果测试集出现比如Tesla这种训练集没有的类别,直接编码就会多出新列,和训练集的特征维度不匹配,模型根本没法用。

下面是几种实用的解决办法:

方法1:用训练集的特征列强制对齐(快速上手)

核心思路是先把训练集编码后的列名存下来,处理测试集时,只保留这些列,缺失的列补0,多余的列直接删掉。

代码示例:

# 第一步:处理训练集并保存特征列
old = pd.DataFrame({"car":["Audi", "BMW", "Mazda"]})
train_dummies = pd.get_dummies(old)
train_feature_cols = train_dummies.columns.tolist()  # 存下训练集的特征列

# 第二步:处理测试集
test = pd.DataFrame({"car":["Audi", "Tesla", "BMW"]})
test_dummies = pd.get_dummies(test)

# 第三步:对齐特征列——保留训练集有的列,缺失补0,多余删除
test_aligned = test_dummies.reindex(columns=train_feature_cols, fill_value=0)
print(test_aligned)

输出结果里,Tesla对应的行三个特征列全是0,完美匹配训练集的特征维度。

方法2:用sklearn的OneHotEncoder(工业界规范做法)

sklearn的OneHotEncoder自带handle_unknown='ignore'参数,专门解决这个问题——遇到训练集没见过的类别时,直接输出全0的编码,不会新增特征列。

代码示例:

from sklearn.preprocessing import OneHotEncoder
import pandas as pd

# 用训练集拟合编码器
old = pd.DataFrame({"car":["Audi", "BMW", "Mazda"]})
encoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore')
encoder.fit(old)  # 关键:必须用训练集拟合,不能碰测试集

# 处理测试集
test = pd.DataFrame({"car":["Audi", "Tesla", "Mazda"]})
test_encoded = encoder.transform(test)

# 转成DataFrame方便查看
test_encoded_df = pd.DataFrame(test_encoded, columns=encoder.get_feature_names_out())
print(test_encoded_df)

这个方法更规范,适合构建完整的机器学习流水线,避免手动处理的疏漏。

方法3:自定义类别映射(适合类别少的场景)

如果你的分类类别不多,可以手动给每个训练集类别分配编码,遇到未知类别时统一映射成全0(或者你也可以专门加一个car_Unknown列,把未知类别映射到这个列)。

代码示例:

import pandas as pd

# 手动定义训练集类别的编码映射
car_code_map = {
    "Audi": [1, 0, 0],
    "BMW": [0, 1, 0],
    "Mazda": [0, 0, 1]
}

# 处理训练集
old = pd.DataFrame({"car":["Audi", "BMW", "Mazda"]})
old_encoded = old["car"].apply(lambda x: pd.Series(car_code_map[x]))
old_encoded.columns = ["car_Audi", "car_BMW", "car_Mazda"]

# 处理测试集——未知类别用[0,0,0]填充
test = pd.DataFrame({"car":["Audi", "Tesla", "BMW"]})
test_encoded = test["car"].apply(lambda x: pd.Series(car_code_map.get(x, [0,0,0])))
test_encoded.columns = ["car_Audi", "car_BMW", "car_Mazda"]
print(test_encoded)

这种方法灵活性高,适合你对类别有明确控制权的小数据集。

额外提醒

  • 绝对不要用测试集拟合编码器:如果在测试集上重新拟合编码,会导致数据泄露,模型的泛化能力会严重下降。
  • 如果未知类别出现频率很高:那你可能需要重新审视训练集,考虑补充这些类别的数据,或者换用更鲁棒的特征编码方式(比如目标编码时也要单独处理未知类别,但独热编码用上面的方法就足够)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:17:36