如何同时使用ColumnTransformer与FeatureUnion 解决交叉验证得分为NaN问题
问题根因排查
交叉验证返回全NaN值由4个代码错误直接导致,按影响优先级排序:
- 预处理模块未接入最终Pipeline:你已定义
preprocessor实现数值特征缩放、分类特征编码,但构建分类器Pipeline时完全没有加入该预处理节点,原始未处理特征直接输入后续环节,未编码的分类特征无法被模型识别,拟合失败后被静默返回为NaN。 - LGBMClassifier参数拼写错误:代码中写的
bagging_freg=1为笔误,正确参数名是bagging_freq,参数不匹配会直接触发模型拟合报错。 - FeatureUnion用法错误:FeatureUnion的作用是并行拼接多个特征处理分支的输出结果,你仅传入了单个特征选择转换器,完全不需要嵌套FeatureUnion,多余层级反而容易触发维度匹配、输入校验异常。
- 存在缺失值隐患:你将OrdinalEncoder的未知类别映射值设为
np.nan,而后续使用的随机森林不支持输入含NaN的特征,即使预处理接入成功也会触发拟合失败。
修正后的可运行代码
import numpy as np from sklearn.pipeline import Pipeline from sklearn.preprocessing import MinMaxScaler, OrdinalEncoder from sklearn.compose import ColumnTransformer from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import RandomForestClassifier from lightgbm import LGBMClassifier from sklearn.model_selection import cross_val_score # 数值、分类特征预处理逻辑 numeric_transformer = Pipeline(steps=[('scale', MinMaxScaler())]) cat_transformer = Pipeline(steps=[ # 未知类别映射为-1,不要设为NaN避免后续模型拟合失败 ('ordinal_enc', OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1)) ]) preprocessor = ColumnTransformer( transformers=[ ('num', numeric_transformer, num_cols), ('cat', cat_transformer, cat_cols) ]) # 按数据流向顺序拼接步骤,移除多余的FeatureUnion嵌套 clf = Pipeline(steps=[ ('preprocess', preprocessor), # 补入之前遗漏的预处理环节 ('feature_selection', SelectFromModel(LGBMClassifier( boosting_type='gbdt', bagging_freq=1, # 修正拼写错误的参数名 objective='multiclass', verbose=-1 ))), ('model', RandomForestClassifier()) ]) # 调试阶段加上error_score='raise',会直接抛出具体错误而非静默返回NaN,方便快速定位问题 scores = cross_val_score(clf, X_train, y_train, cv=5, scoring='accuracy', error_score='raise') print('Accuracy scores:\n', scores) print(scores.mean())
调试提示
- 后续遇到交叉验证返回NaN的情况,优先给
cross_val_score传入error_score='raise'参数,框架会直接抛出拟合过程的具体报错信息,不需要盲目排查问题点。 - 构建Pipeline时需要严格遵循数据流向顺序:原始输入→特征预处理→特征选择/工程→最终模型,定义完成后可逐阶段校验输出维度是否匹配。
- 不支持缺失值的模型(如随机森林、逻辑回归),前置预处理环节必须把所有缺失值、特殊编码值转换为合法数值,不能保留
np.nan。
内容的提问来源于stack exchange,提问作者Kelly
相关产品推荐
相关产品推荐

