均值(目标)编码实现求助:分类特征编码报错排查
解决均值编码中的KeyError问题及数据泄露风险规避
先拆解你遇到的两个错误根源,再给出符合规范的均值编码实现:
第一个错误:KeyError: False
你第一版代码里的cat_features = data.dtypes == 'object'生成的是布尔值Series(索引为列名,值是True/False),而非分类特征的列名列表。当把这个传给mean_encoding函数的cols参数时,循环会误把False当作列名去查找,直接触发KeyError。
正确的分类特征列名获取方式应该是:
cat_features = data.columns[data.dtypes == 'object'].tolist()
第二个错误:KeyError: 'Columns not found: 87.68...'
这个错误背后有两个核心问题:
- 你合并训练集和测试集后已经删除了
y列,但函数里尝试用df.groupby(c)[target]——这里的target是训练集的y数组,并非data中的列,pandas会把target里的数值当作列名去匹配,自然找不到对应列。 - 更严重的是:绝对不能用包含测试集的合并数据集计算均值编码,这会导致严重的数据泄露,测试集的信息会提前混入训练过程,彻底破坏模型的泛化能力。
正确的均值编码实现步骤
我们需要在训练集单独计算每个分类特征的均值映射,再将该映射分别应用到训练集和测试集,同时处理测试集中可能出现的、训练集从未见过的类别。
以下是完整修正代码:
import pandas as pd # 基于你已有的变量拆分训练/测试集 train_data = data.iloc[:split, :].copy() test_data = data.iloc[split:, :].copy() # 将目标变量重新加入训练集(合并时已删除) train_data['y'] = target # 获取分类特征列名列表 cat_features = train_data.columns[train_data.dtypes == 'object'].tolist() def mean_encode_features(train_df, test_df, cat_cols, target_col): # 存储每个分类特征的均值映射规则 mean_mappings = {} for col in cat_cols: # 仅在训练集上计算均值映射,避免数据泄露 mean_map = train_df.groupby(col)[target_col].mean() mean_mappings[col] = mean_map # 应用映射到训练集 train_df[col] = train_df[col].map(mean_map) # 应用映射到测试集,对未见过的类别填充训练集目标变量的全局均值 test_df[col] = test_df[col].map(mean_map).fillna(train_df[target_col].mean()) return train_df, test_df # 执行均值编码 encoded_train, encoded_test = mean_encode_features(train_data, test_data, cat_features, 'y') # 重新合并为最终数据集 data = pd.concat([encoded_train.drop('y', axis=1), encoded_test], axis=0).reset_index(drop=True)
关键细节说明:
- 规避数据泄露:所有均值计算仅基于训练集,测试集完全复用训练集的映射规则,符合真实预测场景。
- 处理未知类别:测试集中出现训练集没有的分类值时,用训练集目标变量的全局均值填充,避免生成NaN影响后续建模。
- 赋值修正:原代码中
df[c].map(means)仅生成临时Series,未赋值回原列,修正后直接覆盖原特征列,确保编码生效。
内容的提问来源于stack exchange,提问作者Stanislav Jirák
相关产品推荐
相关产品推荐

