我想使用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)
答案 0 :(得分:0)
首先,这里只是一个共同发生,因为你选择的random_state
和cv
,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值。