使用K折交叉验证标准化数据

3

我正在使用StratifiedKFold,所以我的代码看起来像这样:

def train_model(X,y,X_test,folds,model):
    scores=[]
    for fold_n, (train_index, valid_index) in enumerate(folds.split(X, y)):
        X_train,X_valid = X[train_index],X[valid_index]
        y_train,y_valid = y[train_index],y[valid_index]        
        model.fit(X_train,y_train)
        y_pred_valid = model.predict(X_valid).reshape(-1,)
        scores.append(roc_auc_score(y_valid, y_pred_valid))
    print('CV mean score: {0:.4f}, std: {1:.4f}.'.format(np.mean(scores), np.std(scores)))
folds = StratifiedKFold(10,shuffle=True,random_state=0)
lr = LogisticRegression(class_weight='balanced',penalty='l1',C=0.1,solver='liblinear')
train_model(X_train,y_train,X_test,repeted_folds,lr)

现在,在训练模型之前,我想要对数据进行标准化。那么,哪种方法是正确的?
1)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

在调用train_model函数之前,需要先执行以下操作:

2)
在函数内部进行标准化处理,代码如下:

def train_model(X,y,X_test,folds,model):
    scores=[]
    for fold_n, (train_index, valid_index) in enumerate(folds.split(X, y)):
        X_train,X_valid = X[train_index],X[valid_index]
        y_train,y_valid = y[train_index],y[valid_index]
        scaler = StandardScaler()
        X_train = scaler.fit_transform(X_train)
        X_vaid = scaler.transform(X_valid)
        X_test = scaler.transform(X_test)
        model.fit(X_train,y_train)
        y_pred_valid = model.predict(X_valid).reshape(-1,)

        scores.append(roc_auc_score(y_valid, y_pred_valid))

    print('CV mean score: {0:.4f}, std: {1:.4f}.'.format(np.mean(scores), np.std(scores)))

根据我的了解,在第二个选项中,我不会泄露数据。如果我不使用pipeline,哪种方法是正确的?如果我想使用交叉验证,该如何使用pipeline?

2个回答

3

实际上,第二个选项更好,因为缩放器不会看到 X_valid 的值来缩放 X_train

如果您使用管道,则可以执行以下操作:

from sklearn.pipeline import make_pipeline

def train_model(X,y,X_test,folds,model):
    pipeline = make_pipeline(StandardScaler(), model)
    ...

使用pipeline而不是model。在每次fitpredict调用时,它会自动标准化手头的数据。

请注意,您还可以使用scikit-learn中的cross_val_score函数,并使用参数scoring='roc_auc'


如果我想使用cross_val_score,首先我必须创建folds = StratifiedKFold(10, shuffle=True, random_state=0),然后使用StandardScaler和模型(model)来创建pipeline。之后,使用cross_val_score(pipeline, X, y, cv=folds, scoring='roc_auc')。这里的X和y表示整个训练数据,对吗? - Utsav Patel
是的,整个训练数据会自动处理分割,根据你传递给cv参数的情况,例如使用交叉验证分割器。 - Horace
如果我使用 cross_val_score 那么就不需要使用 for 循环和 folds.splits(X,y) 了,它们是同一回事,对吗? - Utsav Patel
@Utsav Patel 对不起,我删除了我的答案,因为我担心我的回答可能不够清楚。你可以在这里找到我实际意思的内容,希望对你有所帮助: https://stats.stackexchange.com/questions/27627/normalization-prior-to-cross-validation - 4.Pi.n

0
如果你的数据很大,那么这可能并不太重要(如果你使用k折交叉验证可能不是这种情况),但既然可以,最好在交叉验证(k折)或选项2中进行。此外,更多关于交叉验证中过拟合的信息,请参考this

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接