使用带有sklearn的GroupKFold进行嵌套交叉验证

问题描述

在我的数据中,有多个条目对应于一个主题,我不会在训练和测试集之间混合这些条目。因此,我查看了GroupKFold折叠迭代器,根据sklearn文档,这是“具有不重叠组的K折叠迭代器变体。” 因此,我想使用GroupKFold来实现嵌套交叉验证,以拆分测试和训练集。

我从this question中给出的模板开始。但是,我在调用网格实例上的fit方法时遇到错误,说groups的形状与Xy不同。为了解决这个问题,我也使用火车索引对groups进行了切片。

此实现正确吗?我最关心的是不要在训练和测试集之间混合来自同一组的数据。

inner_cv = GroupKFold(n_splits=inner_fold)
outer_cv = GroupKFold(n_splits=out_fold)


for train_index,test_index in outer_cv.split(x,y,groups=groups):
    x_train,x_test = x[train_index],x[test_index]
    y_train,y_test = y[train_index],y[test_index]

    grid = RandomizedSearchCV(estimator=model,param_distributions=parameters_grid,cv=inner_cv,scoring=get_scoring(),refit='roc_auc_scorer',return_train_score=True,verbose=1,n_jobs=jobs)
    grid.fit(x_train,y_train,groups=groups[train_index])
    prediction = grid.predict(x_test)

解决方法

可以确认代码正在按预期方式运行(即不在组之间混合数据)的一种方法是,不能传递GroupKFold对象,而可以传递GroupKFold.split的输出(索引)到RandomizedSearchCV。例如

grid = RandomizedSearchCV(estimator=model,param_distributions=parameters_grid,cv=inner_cv.split(
                              x_train,y_train,groups=groups[train_index]),scoring=get_scoring(),refit='roc_auc_scorer',return_train_score=True,verbose=1,n_jobs=jobs)
grid.fit(x_train,y_train)

我相信这会导致相同的拟合结果,在这里,您已经明确给出了交叉验证每一折的训练/验证索引。

据我所知,这两种方式是等效的,但是我认为编写示例的方式更加优雅,因为您没有两次提供x_trainy_train

使用groups切片train_index似乎是正确的,因为您只将切片的xy变量传递给fit方法。我必须提醒自己,内部交叉验证将在外部交叉验证操作的训练子集上进行交叉验证。