使用 GridSearchCV 进行目标缩放

target scaling using GridSearchCV

对于超参数调整,我使用 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 如何处理引擎盖下的缩放。

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

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])