LinearRegression场景下Cross-Validation与GridSearchCV得分差异问题咨询
得分差异的核心原因
- GridSearchCV嵌套逻辑错误,预处理流程存在数据泄露
你现有pipeline2的结构为[预处理器 -> GridSearchCV],调用fit时预处理器会先用全部训练集完成拟合,再把转换后的数据传入GridSearchCV做内部交叉验证。这导致GridSearchCV内部每个验证折的信息都提前泄露给了预处理器,和你直接把完整pipeline传入cross_val_score的计算逻辑完全不一致:后者每个折的预处理器只会拟合当前训练折的数据,无信息泄露,得分计算是无偏的。 - 特征预处理逻辑错误,引入冗余噪声
你的ColumnTransformer中同时对surface列做了log转换、标准化两个独立处理,最终会输出两个和surface相关的特征,而非你预期的「先log再标准化」的处理逻辑。错误的特征输入会放大两种交叉验证逻辑的结果偏差。 - 冗余的重复fit调用引入随机偏差
你提供的GridSearch代码中连续两次调用了pipeline2.fit,即使固定了KFold的随机种子,预处理器的浮点精度误差、低版本编码类的随机逻辑也可能导致结果出现偏差。
修复方案
- 修正GridSearchCV的嵌套逻辑,将完整的建模pipeline(预处理器+模型)作为GridSearchCV的估计器,保证交叉验证每个折的预处理逻辑独立:
# 定义基础建模pipeline,和cross_val_score用的结构完全对齐 base_pipeline = Pipeline(steps =[ ('preprocessor', preprocessor), ('model', TransformedTargetRegressor( regressor = LinearRegression(), func = np.log, inverse_func = np.exp )) ]) # 传入GridSearchCV grid_search = GridSearchCV( estimator=base_pipeline, param_grid= {'model__regressor__fit_intercept':[True, False],'model__regressor__normalize': [True, False]}, cv = KFold(n_splits = 23, shuffle = True, random_state=100), scoring = 'r2', refit = True ) grid_search.fit(X_train, y_train) # 输出最优得分,和手动交叉验证结果对齐 print(grid_search.best_score_)
- 修正预处理逻辑,避免特征重复处理,如果需要对
surface先做log再标准化,可通过嵌套Pipeline实现:
preprocessor = ColumnTransformer(transformers=[ # surface列单独做log+标准化 ('surface_process', Pipeline(steps=[ ('log', FunctionTransformer(np.log, inverse_func = np.exp, check_inverse = True)), ('scale', StandardScaler()) ]), ['surface']), # 其他数值列直接标准化 ('num_scaler', StandardScaler(),['years', 'steam_p', 'elec_p']), ('onehotencoder', OneHotEncoder(), ['type']), ('ordinalencoder', OrdinalEncoder(),['nfloors']) ])
- 删除代码中重复的
fit调用,保证单次拟合流程的一致性。
完成以上调整后,GridSearchCV的最优得分会和手动交叉验证的结果持平或更优。
内容的提问来源于stack exchange,提问作者Rococo
相关产品推荐
相关产品推荐

