StandardScaler 到整个训练数据集或单个折叠以进行交叉验证

Ale*_*rry 5 python scikit-learn cross-validation k-fold

我目前正在使用 cross_val_score 和 KFold 来评估在数据预处理中的不同点使用 StandardScaler 的影响,特别是在执行交叉验证之前缩放整个训练数据集是否会导致数据泄漏,以及与缩放相比有何影响来自管道内的数据(因此仅将其应用于训练折叠)。

我目前的流程如下:

实验A

  • 从 sklearn.datasets 导入波士顿住房数据集并拆分为数据 (X) 和目标 (y)
  • 创建一个 Pipeline (sklearn.pipeline),在应用线性回归之前应用 StandardScaler
  • 指定交叉验证方法为 KFold 5 折
  • 使用上述Pipeline和KFold方法进行交叉验证(cross_val_score)并观察分数

实验B

  • 使用与上面相同的波士顿住房数据
  • 整个数据集上的 fit_transform StandardScaler
  • 使用 cross_val_Score 再次执行交叉验证 5 倍,但这次直接输入 LinearRegression 而不是管道
  • 将此处的分数与实验 A 进行比较

获得的分数是相同的(大约小数点后 13 位),我对此表示怀疑,因为实验 B 在交叉验证过程中肯定会引入数据泄漏。

我看过帖子指出,在交叉验证之前是否对整个训练集进行缩放并不重要,如果这是真的,我想了解为什么,如果这不是真的,我想了解为什么分数数据泄露了还能这么相似吗?

请参阅下面我的测试代码:

import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn import datasets

from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
from sklearn.model_selection import KFold, StratifiedKFold

from sklearn.model_selection import cross_val_score, cross_val_predict

from sklearn.linear_model import LinearRegression

np.set_printoptions(15)

boston = datasets.load_boston()
X = boston["data"]
y = boston["target"]
Run Code Online (Sandbox Code Playgroud)
scalar = StandardScaler()
clf = LinearRegression()

class StScaler(StandardScaler):
    def fit_transform(self,X,y=None):
        print('Length of Data on which scaler is fit on =', len(X))
        output = super().fit(X,y)
#         print('mean of scalar =',output.mean_)
        output = super().transform(X)
        return output


pipeline = Pipeline([('sc', StScaler()), ('estimator', clf)])

cv = KFold(n_splits=5, random_state=42)

cross_val_score(pipeline, X, y, cv = cv)

Run Code Online (Sandbox Code Playgroud)
# Now fitting Scaler on whole train data
Run Code Online (Sandbox Code Playgroud)
scaler_2 = StandardScaler()
clf_2 = LinearRegression()

X_ss = scaler_2.fit_transform(X)
cross_val_score(clf_2, X_ss, y, cv=cv)
Run Code Online (Sandbox Code Playgroud)

谢谢!