我应该在 kfold 验证设置中在哪里定义 sklearn 模型?

问题描述

我是机器学习的新手,我对 K 折交叉验证感到困惑。当我编写 fold for 循环时,我应该在哪里定义 sklearn 模型(而不是 PyTorch 模型)。我看过一些教程,他们在 fold for 循环中定义模型并使用相同的模型预测 X_validation。但随后我们将在 for 循环中定义 k 不同的模型,最终模型将是仅在最后一次折叠上训练的模型,它与前一次折叠没有任何联系。

  • 在我看来,我们应该在 Kfold 交叉验证之外定义一个 Scikitlearn 模型,请向我解释我的想法是否正确,或者是否存在与此方法相关的任何数据泄漏问题?

下面是我在我的项目中使用的实现,这里我在 kfold for loop 中定义了 sklearn-model。

import pandas as pd
from sklearn import linear_model
from sklearn import metrics

import config 
from lr_pipeline import lr_pipe

def run_training(fold):
    # load a single fold here
    df = pd.read_csv(config.TRAIN_FOLDS)
    df_train = df[df.kfold != fold].reset_index(drop=True)
    df_val = df[df.kfold == fold].reset_index(drop=True)

    # get X_train,X_val,y_train and y_val
    X_train = df_train.drop(['id','target_class','kfold'],axis=1)
    y_train = df_train['target_class']

    X_val = df_val.drop(['id',axis=1)
    y_val = df_val['target_class']

    # preprocessing pipeline here
    X_train = lr_pipe.fit_transform(X_train)
    X_val = lr_pipe.transform(X_val)

    # train clf
    clf = linear_model.LogisticRegression()
    clf.fit(X_train,y_train)

    # metric
    pred = clf.predict_proba(X_val)[:,1]
    auc = metrics.roc_auc_score(y_val,pred)
    print(f"fold={fold},auc={auc}")

    df_val.loc[:,"lr_pred"] = pred
    return df_val[["id","kfold","target_class","lr_pred"]]

if __name__ == '__main__':
    dfs = []
    for i in range(5):
        temp_df = run_training(i)
        dfs.append(temp_df)
    fin_valid_df = pd.concat(dfs)


    print(fin_valid_df.shape)
    fin_valid_df.to_csv(config.LR_MODEL_PRED,index=False)

解决方法

让我从一个简短的背景开始。大多数机器学习模型都有两组参数:

首先,所谓的超参数,例如对于线性回归 - 正则化系数 alpha,对于决策树 - 树的 depth,对于 K 个最近邻 (KNN) - number of neighbors

其次,模型有参数,例如对于线性回归 - 权重(w 和 b 在 X w + b 中),对于决策树 - 在每个树级别进行特定拆分,KNN 是没有任何参数的模型的罕见情况。

模型参数是通过学习算法估计的(这是您键入 model.fit(X,y) 时发生的情况),但是超参数不是。超参数由用户定义。问题是,如何选择它们,答案是交叉验证。它可以是 k 折交叉验证,也可以是任何其他验证技术,例如训练测试拆分或随机洗牌等。

所以,关于你最初的问题。虽然在不同折叠上训练的两个模型的超参数可能相同,但参数会有所不同,因为参数是通过学习推导出来的来自训练数据的算法。因此,无论您是在 for 循环内部还是外部创建模型都没有关系,在不同折叠上训练的模型将是独立且不同的。但交叉验证的目标不是训练模型,而是定义一组最佳超参数。

然而,我越来越多地看到人们如何在不同的折叠上训练模型平均而不在整个训练集上重新训练模型,从而减少预测的方差,在这种情况下,在 for循环并保存实例以备后用,如下所示:

def run_training(fold):
    ...
    clf = linear_model.LogisticRegression()
    clf.fit(X_train,y_train)
    pred = clf.predict_proba(X_val)[:,1]
    return clf

我建议您坚持这种方法,并执行以下操作:

clfs = []
aucs_train = []
aucs_val = []
for train,val in kf.split(X,y):
    clf = run_training(train)
    clfs.append(clf)
    y_pred_train = clf.predict(X[train])[:,1]
    y_pred_val = clf.predict(X[val])[:,1]
    aucs_train.append(auc(y[train],y_pred_train))
    aucs_val.append(auc(y[val],y_pred_val))

在这种情况下,clfs 将包含在不同折叠上训练的分类器,您可以将它们用于验证和预测保留/测试集。