自定义模型与StandardScaler构建Pipeline时预测未反归一化问题
问题根源分析
你的问题核心是对Sklearn Pipeline的工作逻辑和自定义模型角色的理解偏差:
Sklearn的StandardScaler仅负责输入特征X的标准化,不会对模型的输出结果做任何逆变换操作。
- 对于
Lasso这类标准回归模型:它在训练时学习的是标准化后的X到原始尺度y_true的映射关系,所以预测时,即使输入X被标准化,Lasso输出的依然是匹配y_true尺度的预测值。 - 而你的自定义
mean_stacker:它的predict方法直接返回标准化后X的行均值——这个值的尺度是标准化后的(均值为0、方差为1),和原始y_true的尺度完全不匹配,所以看起来像是没做反归一化。
两种修复方案
方案一:让自定义模型学习标准化特征到y的映射(推荐)
如果你想让mean_stacker和Lasso一样在Pipeline中配合StandardScaler工作,需要让模型学习「标准化后的X均值」到「原始y尺度」的线性映射,而不是直接返回X的均值。修改后的模型代码如下:
class mean_stacker(): def __init__(self, desc='Simple Mean Stacker'): self.description = desc def predict(self, X): check_is_fitted(self, ['coef_', 'intercept_']) X = check_array(X) # 计算标准化后X的行均值 x_mean = np.mean(X, axis=1) # 用训练好的系数映射回y的原始尺度 return self.coef_ * x_mean + self.intercept_ def fit(self, X, y): X, y = check_X_y(X, y) # 把每个样本的X均值作为单独特征,拟合线性模型 x_mean = np.mean(X, axis=1).reshape(-1, 1) from sklearn.linear_model import LinearRegression lr = LinearRegression(fit_intercept=True) lr.fit(x_mean, y) # 保存线性模型的系数和截距 self.coef_ = lr.coef_[0] self.intercept_ = lr.intercept_[0] # 标记模型已拟合 self.is_fitted_ = True return self
这个修改后的模型会在训练时自动学习标准化特征到原始y的映射关系,预测时输出的结果会和y_true的尺度完全对齐。
方案二:移除Pipeline中的StandardScaler(适合简单场景)
如果你的mean_stacker只是想直接对原始输入X取均值作为预测值,那么它根本不需要特征标准化(取均值的操作不受特征尺度影响)。此时可以直接使用模型,不需要用Pipeline包裹Scaler:
stacker_models =[ make_pipeline(StandardScaler(), Lasso(alpha = 0.0005, random_state = 4)), mean_stacker() ]
这样mean_stacker的predict会直接返回原始X的行均值,和y_true的尺度自然匹配。
验证效果
修改后运行你的代码,绘制的图表中yMean会和ytrue的趋势、尺度完全一致,不再出现明显偏移。
内容的提问来源于stack exchange,提问作者Phun
相关产品推荐
相关产品推荐

