问题现象描述
当开发者调用eli5.explain_prediction_voting()方法解释投票分类器或随机森林等集成模型的预测结果时,常遇到以下报错:
ValueError: Feature names mismatch: expected ['feature_1', 'feature_2'], got ['col_1', 'col_2']
这种特征名称不匹配问题通常发生在以下场景:
- 使用sklearn管道(Pipeline)进行特征预处理后
- 训练数据和预测数据的列名规范不一致
- 模型从pickle文件加载后特征名丢失
根本原因分析
该问题的核心在于模型特征空间与实际输入数据的维度标识不匹配。eli5库在解析模型时需要:
- 访问训练阶段记录的特征名称元数据
- 验证预测输入数据的列名顺序一致性
- 匹配预处理阶段生成的特征工程映射关系
当这三个条件任一不满足时,就会触发特征名称异常。
解决方案
方法一:显式设置特征名称
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
# 创建管道时保留特征名
pipe = make_pipeline(
StandardScaler(),
RandomForestClassifier()
).set_output(transform="pandas") # 关键设置
方法二:自定义特征名转换器
class FeatureNameKeeper(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
self.feature_names_ = X.columns.tolist()
return self
def transform(self, X):
return X
# 在管道首位添加转换器
pipe.steps.insert(0, ('name_keeper', FeatureNameKeeper()))
方法三:后处理修复
对于已训练的模型,可以通过模型属性注入修复:
# 从训练数据获取特征名
feature_names = X_train.columns.tolist()
# 注入到已训练的模型
if hasattr(model, 'feature_names_in_'):
model.feature_names_in_ = np.array(feature_names)
elif hasattr(model, 'feature_importances_'):
model._feature_names = feature_names
预防措施
| 场景 | 最佳实践 |
|---|---|
| 使用ColumnTransformer | 设置verbose_feature_names_out=False |
| 持久化模型 | 同时保存特征名称列表 |
| 跨版本兼容 | 使用get_feature_names_out()方法 |
深度技术解析
该问题的本质是scikit-learn生态系统的元数据传播机制缺陷。在特征工程流水线中:
- OneHotEncoder会修改特征空间维度
- PCA等降维方法会丢弃原始特征名
- FeatureUnion会拼接多个特征源
eli5的解释器核心需要重建完整的特征映射链,因此对名称一致性要求严格。理解这一机制有助于从根本上避免问题。