【问题标题】:target scaling using GridSearchCV使用 GridSearchCV 进行目标缩放
【发布时间】:2026-01-21 17:50:01
【问题描述】:

对于超参数调整,我使用 Python 包 sklearn 中的函数 GridSearchCV。我测试的一些模型需要特征缩放(例如支持向量回归 - SVR)。最近,在 Udemy 的课程Machine Learning A-Z™: Hands-On Python & R In Data Science中,讲师提到对于 SVR,目标也应该进行缩放(如果它不是二进制的)。考虑到这一点,我想知道目标是否在GridSearchCV 执行的交叉验证过程的每次迭代中也被缩放,或者是否只有特征被缩放。请参阅下面的代码,它说明了我用于对需要缩放训练集的估计器进行超参数调整的正常过程:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVR
    
def SVRegressor(**kwargs):
   '''contruct a pipeline to perform SVR regression'''
   return make_pipeline(StandardScaler(), SVR(**kwargs))

params = {'svr__kernel': ["poly", "rbf"]}
grid_search = GridSearchCV(SVRegressor(), params)
grid_search.fit(X, y)

我知道我可以简单地扩展 Xy 先验,然后从管道中删除 StandardScaler。但是,我想在测试多个模型的代码管道中实现这种方法,其中一些需要缩放,而另一些不需要。这就是为什么我想知道GridSearchCV 如何在后台处理缩放。

【问题讨论】:

    标签: python python-3.x scikit-learn svm gridsearchcv


    【解决方案1】:

    不,它不会缩放目标,如果您查看 make_pipeline,它只是将 X 和 y 参数传递给您的转换器,而 StandardScaler() 对您的 y 没有任何作用:

    def _fit_transform_one(transformer,
                           X,
                           y,
                           weight,
                           message_clsname='',
                           message=None,
                           **fit_params):
        """
        Fits ``transformer`` to ``X`` and ``y``. The transformed result is returned
        with the fitted transformer. If ``weight`` is not ``None``, the result will
        be multiplied by ``weight``.
        """
        with _print_elapsed_time(message_clsname, message):
            if hasattr(transformer, 'fit_transform'):
                res = transformer.fit_transform(X, y, **fit_params)
            else:
                res = transformer.fit(X, y, **fit_params).transform(X)
    
        if weight is None:
            return res, transformer
        return res * weight, transformer
    

    你可以在 StandardScaler() 上试试这个,你会发现它对 y 没有任何作用:

    np.random.seed(111)
    X = np.random.normal(5,2,(100,3))
    y = np.random.normal(5,2,100)
    
    res = StandardScaler().fit_transform(X=X,y=y)
    res.shape
    (100, 3)
    
    res.mean(axis=0)
    array([1.01030295e-15, 4.39648318e-16, 8.91509089e-16])
    
    res.std(axis=0)
    array([1., 1., 1.])
    

    你也可以查看你的 gridsearchcv 的结果:

    SVRegressor = make_pipeline(StandardScaler(), SVR())
    params = {'svr__kernel': ["poly", "rbf"]}
    grid_search = GridSearchCV(SVRegressor, params,
    scoring='neg_mean_absolute_error')
    

    在未缩放的 y 上,您会看到在未缩放的数据上,您的负平均绝对误差与您的标准差大致相同(我在示例中使用了 2):

    grid_search.fit(X, y)
    
    grid_search.cv_results_['mean_test_score']
    array([-2.01029707, -1.88779205])
    

    在缩放 y 上,我们的标准差为 1,您可以看到误差在 -1 左右:

    y_scaled = StandardScaler().fit_transform(y.reshape(-1,1)).ravel()
    grid_search.fit(X, y_scaled)
    
    grid_search.cv_results_['mean_test_score']
    array([-1.00585999, -0.88330208])
    

    【讨论】: