添加SelectKBest后模型性能骤降且出现除零警告问题排查
问题分析与解决方案
核心问题1:Pipeline执行顺序完全错误
你把SelectKBest放在了DecisionTreeRegressor之后,这是逻辑错误——特征选择的作用是筛选输入模型的特征,应该先做特征选择,再训练模型。当前流程是先训练模型,再对模型的输出做特征选择,完全偏离了优化模型的目的,这是性能暴跌的主要原因。
核心问题2:特征选择方法不匹配任务类型
你用了f_classif,这是针对分类任务的ANOVA F检验方法,而你的任务是回归,应该使用专门针对回归任务的f_regression。用错方法会导致筛选出的特征与回归目标无关,进一步拉低模型性能。
除零警告的原因
RuntimeWarning: divide by zero encountered in true_divide是因为部分特征在计算F值时,组内均方(msw)为0,比如某分类特征编码后,某个类别只有单一样本,或者特征本身方差为0,导致除法运算出现除零。
修正后的代码
from sklearn.feature_selection import SelectKBest, f_regression # 替换f_classif为f_regression from sklearn.tree import DecisionTreeRegressor from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.impute import SimpleImputer from sklearn.preprocessing import MinMaxScaler, OneHotEncoder from sklearn.model_selection import KFold, GridSearchCV numeric_features = ['AGE_2019', 'Inhabitants'] categorical_features = ['familty_type','studying','Job_42','sex','DEGREE', 'Activity_type', 'Nom de la commune', 'city_type', 'DEP', 'INSEE', 'Nom du département', 'reg', 'Nom de la région'] numeric_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='median')), ('scaler', MinMaxScaler()) ]) categorical_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='constant',fill_value='missing')), ('encoder', OneHotEncoder(handle_unknown='ignore')) ]) preprocessor = ColumnTransformer( transformers=[ ('numeric', numeric_transformer, numeric_features), ('categorical', categorical_transformer, categorical_features) ]) # 修正Pipeline顺序:预处理 → 特征选择 → 模型 pipe = Pipeline([ ('preprocessor', preprocessor), ('selector', SelectKBest(f_regression, k=7)), # 移到模型前,替换为f_regression ('model', DecisionTreeRegressor(random_state=0)) ]) dt_params = {'model__min_samples_split': [2, 5] + list(range(10, 250,5))} cv_folds = KFold(n_splits=5, shuffle=True, random_state=0) grid_piped = GridSearchCV(pipe, dt_params, cv=cv_folds, n_jobs=-1, scoring=['neg_mean_squared_error', 'r2'], refit='r2') grid_piped.fit(df_X_train,df_Y_train)
额外优化建议
- 调整k值:当前固定k=7,建议把k加入网格搜索参数(比如
selector__k: [5,7,10,15]),让模型自动选择最优的特征数量。 - 过滤低方差特征:在预处理后、特征选择前加入
VarianceThreshold(threshold=0),去掉方差为0的特征,避免除零警告:from sklearn.feature_selection import VarianceThreshold pipe = Pipeline([ ('preprocessor', preprocessor), ('var_filter', VarianceThreshold(threshold=0)), # 新增低方差过滤 ('selector', SelectKBest(f_regression, k=7)), ('model', DecisionTreeRegressor(random_state=0)) ]) - 尝试其他特征选择方法:比如
SelectFromModel结合树模型,更适配决策树的特征重要性逻辑。
内容的提问来源于stack exchange,提问作者Gaspard_Boyer
相关产品推荐
相关产品推荐

