首页 文章

使用scikit-learn中的管道扩展数据:StandardScaler与RobustScaler

提问于
浏览
0

我想使用GridSearchCV来确定具有L1正则化的逻辑回归中的最优正则化参数“C” . 我还想扩展/标准化我的输入功能 .

在执行交叉验证之前,使用单个转换缩放整个训练数据集导致数据泄漏:在交叉验证中,训练数据集被划分为k个折叠,每个折叠被视为验证数据集一次,而其他的则是训练折叠 . 但是,如果在整个训练数据集的交叉验证之前完成标准化,则每个折叠(包括验证折叠)将使用从整个训练数据集计算的参数(例如,平均值和标准偏差)进行缩放,所以在某种程度上,训练折叠总是“知道一些”关于验证折叠 .

因此,缩放数据的适当方式是分别计算和应用每个交叉验证折叠的缩放(即,在内部训练折叠上,在每次迭代中保持验证折叠) . 在scikit-learn中,这可以使用管道完成 .

我实现了一个测试用例,以查看两种方法之间的差异(“不正确的缩放”与“使用管道进行适当的缩放”),并且在使用StandardScaler时,无论方法如何,得到的回归系数都是相同的,我发现这令人惊讶 . 但是,使用RobustScaler时,结果系数不同 .

为什么“流水线”扩展会对RobustScaler产生影响,但对于StandardScaler却没有?

谢谢!

这是我的测试用例:

import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import RobustScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.datasets import load_breast_cancer

# Choose between the two scalers:
# scaler = RobustScaler()
scaler = StandardScaler()  

C_values = [0.001, 0.01, 0.05, 0.1, 1., 100.]

cancer = load_breast_cancer()
X, y = cancer.data, cancer.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

###########################################
# Version A: Proper scaling with pipeline #
###########################################

param_grid = {'logisticregression__C': C_values}

logReg = LogisticRegression(fit_intercept=True, 
                            penalty='l1', 
                            solver='liblinear', 
                            tol=0.0001, 
                            max_iter=1000, 
                            random_state=0)

# Create a pipeline that scales, then runs logistic regression
pipeline = make_pipeline(scaler, logReg)

vA = GridSearchCV(pipeline, param_grid=param_grid,
                     scoring='roc_auc', cv=10, refit=True)
vA.fit(X_train, y_train)

# Get coefficients
coefA = vA.best_estimator_.named_steps['logisticregression'].coef_

###############################
# Version B: Improper scaling #     
###############################

param_grid = {'C': C_values}

X_train_scaled = scaler.fit_transform(X_train)

vB = GridSearchCV(logReg, param_grid=param_grid,
                     scoring='roc_auc', cv=10, refit=True)
vB.fit(X_train_scaled, y_train)

# Get coefficients
coefB = vB.best_estimator_.coef_


# Compare coefficients
# (Assertion will pass for StandardScaler, but 
# fail for RobustScaler)
assert np.array_equal(coefA, coefB)

1 回答

  • 0

    首先,这里只是一个共同发生的标准,因为你选择了 random_statecv ,StandardScaler不会改变coef_的值 . 如果将 cv=10 更改为cv = 3或4并删除 random_state ,则还会为StandardScaler获取不同的 coef_ 值 .

    现在讲解一下:

    你看,第一种方法在这里观察的线是:

    vA.fit(X_train, y_train)
    

    现在vA是一个gridsearch,它将通过将X_train,y_train分成更多的训练和测试并找到最佳参数然后拟合整个 X_train, y_train 来进行交叉验证 . 这意味着管道将适合整个数据 . 因此,使用StandardScaler或RobustScaler并不重要 .

    现在在方法2中你正在做:

    X_train_scaled = scaler.fit_transform(X_train)
    

    因此,您在两种方法中使用缩放器上的相同数据 . 两种方法中的缩放器将适合完全相同的数据并且学习完全相同的 scale_mean_ 或其他属性 .

    因此,让我们检查是否适合完全相同的LogisticRegression .

    在你的方法1中执行此操作:

    >> print(vA.best_params_)
    #Output: {'logisticregression__C': 1.0}
    

    这方法2:

    >> print(vB.best_params_)
    #Output: {'C': 1}   for StandardScaler
    #Output: {'C': 0.1}   for RobustScaler
    

    所以你看, coef_ 的差异是由于LogReg中 C 的差异造成的 . grid_search在StandardScaler中找到的最佳 C 在两种方法中都相同(等于1.0),但不适用于RobustScaler .

    因此,GridSearchCV中发生的内部分裂然后传递给RobustScaler,后者以不同的方式缩放数据,因此发现不同的C是最佳的 .

相关问题