使用RandomizedSearchCV优化LGBM多分类模型时特征不匹配报错求解
问题解决:带自定义评分的RandomizedSearchCV优化LGBM多分类模型报错处理
问题场景
要通过带自定义评分函数的RandomizedSearchCV优化多分类LGBM模型,自定义评分需要额外的scoring_info_cols数据(仅用于分数计算,不可用于模型训练)。features_train和features_val均包含训练特征+这些额外列,但调用random_search.fit()时出现以下错误:
ValueError: Length of feature_name(25) and num_feature(7) don't match
其中7是训练用特征数,25是7个训练特征加18个额外scoring_info列,推测ColumnTransformer仅处理了训练数据,未处理验证集。
错误原因
你的判断完全正确:Pipeline只会对fit()传入的主训练数据(features_train)执行前置的drop_scoring_info处理,但通过lgbm__eval_set传入的验证集是原始的features_val,包含全部25列。而LGBM训练时已经适配了7列的训练特征,验证集特征数不匹配就会触发报错。
解决方案
方案1:提前预处理验证集(简单直接)
先使用同一个ColumnTransformer处理验证集,确保训练和验证的特征数一致:
# 先让dropper拟合训练数据,保证处理逻辑一致 dropper.fit(features_train) # 处理验证集,移除scoring_info_cols features_val_processed = dropper.transform(features_val) # 修改fit调用,传入处理后的验证集 random_result = random_search.fit( features_train, target_train, lgbm__eval_set=[(features_val_processed, target_val)], lgbm__eval_metric=my_eval_metric )
方案2:自定义LGBM包装器(适配交叉验证场景)
如果使用交叉验证(cv=5),每折的验证集都需要单独处理,提前预处理会比较繁琐。可以自定义一个包装类,让LGBM在训练时自动对eval_set执行前置预处理:
from sklearn.base import BaseEstimator, ClassifierMixin import lightgbm as lgb class LGBMWithEvalPreprocess(BaseEstimator, ClassifierMixin): def __init__(self, preprocessor, lgb_params=None): self.preprocessor = preprocessor self.lgb_params = lgb_params or {} self.model = lgb.LGBMClassifier(**self.lgb_params) def fit(self, X, y, eval_set=None, eval_metric=None, **fit_params): # 预处理训练数据 X_processed = self.preprocessor.fit_transform(X) # 预处理验证集(如果传入) processed_eval_set = [] if eval_set is not None: for X_val, y_val in eval_set: X_val_processed = self.preprocessor.transform(X_val) processed_eval_set.append((X_val_processed, y_val)) # 调用LGBM原生fit方法 self.model.fit(X_processed, y, eval_set=processed_eval_set, eval_metric=eval_metric, **fit_params) return self def predict(self, X): X_processed = self.preprocessor.transform(X) return self.model.predict(X_processed) def predict_proba(self, X): X_processed = self.preprocessor.transform(X) return self.model.predict_proba(X_processed) # 重新构建模型 dropper = ColumnTransformer( [("drop", "drop", scoring_info_cols)], remainder="passthrough" ) lgbm_model = LGBMWithEvalPreprocess( preprocessor=dropper, lgb_params={"early_stopping_rounds": 20} ) # RandomizedSearchCV配置不变,fit时直接传原始验证集 random_search = RandomizedSearchCV( lgbm_model, param_distributions=param_dist, cv=5, scoring=custom_scoring_function, n_iter=100, random_state=42, n_jobs=1 ) random_result = random_search.fit( features_train, target_train, eval_set=[(features_val, target_val)], eval_metric=my_eval_metric )
自定义评分函数注意事项
因为RandomizedSearchCV的自定义评分函数会接收原始的X(包含scoring_info_cols)、y_true和模型,所以你可以直接在custom_scoring_function中从X提取所需的额外列,结合模型预测结果计算分数,无需额外处理。
内容的提问来源于stack exchange,提问作者riccio777
相关产品推荐
相关产品推荐

