交叉验证性能是否可以准确指示预测独立数据集的真实性能?

数据挖掘 xgboost 交叉验证
2021-09-14 07:38:31

我觉得这个问题与交叉验证背后的理论有关。我在这里展示了我的经验发现,并在那里写了一个与交叉验证理论相关的问题

我有两个模型 M1 和 M2,我使用相同的数据集来训练它们并使用相同的数据集执行交叉验证以找到每个模型的最佳参数。最后说一下,我发现 M1 在其最佳参数下,在 10 倍交叉验证分数方面比 M2 在其最佳参数下表现更好。现在,如果我有另一个包含预测变量和标签的独立测试数据集,并且该测试数据集是从我的训练数据集的相同分布中生成的,那么在我将这两个经过良好调整的模型应用于该新测试数据集之前,我可以声明还是我应该期望看到 M1 在那个新的测试数据集上仍然会比 M2 表现更好?

我在玩 Kaggle Titanic 的例子。我有 2 个 xgboost 模型,M1 调整良好,M2 调整得不太好,因为 M1 在训练数据集上执行了更好的 10 倍交叉验证。但是当我同时提交两者时,我发现调整得不太好的模型实际上在测试数据集上的得分更高。怎么可能?如果这是真的,那么当我们将数据拟合到不同的模型并调整模型参数时,我们应该寻找什么?

以下是我的具体提交结果:我做了一个随机网格搜索

params_fixed = {'silent': 1,'base_score': 0.5,'reg_lambda': 1,
'max_delta_step': 0,'scale_pos_weight':1,'nthread': 4,
'objective': 'binary:logistic'}
params_grid = {'max_depth': list(np.arange(1,10)),
'gamma': [0,0.05,0.1,0.3, 0.5,0.7,0.9],
'n_estimators':[1,2,5,7,10,15,19,25,30,50], 
'learning_rate': [0.01,0.03,0.05,0.1,0.3,0.5,0.7,0.9,1],
'subsample': [0.5,0.7,0.9], 'colsample_bytree': [0.5,0.7,0.9], 
'min_child_weight': [1,2,3,5], 'reg_alpha': [1e-5, 1e-2, 0.1, 0.5,1,10]
}
rs_grid = RandomizedSearchCV(
          estimator=XGBClassifier(**params_fixed, seed=seed),
          param_distributions=params_grid,
          n_iter=5000,   
          cv=10,
          scoring='accuracy',
          random_state=seed
)

每次我更改变量时n_iter首先,我设置n_iter=10,它给了我一组这些超参数的值,我们称之为向量α1并且 cv 分数(准确率)为0.83389,然后我使用α1训练我的模型并在独立的测试数据集上生成预测,当我提交给 Kaggle 时,它​​会在测试数据集0.79426上生成真实准确度

其次,我设置n_iter=100,它给了我α2并且 cv 分数是0.83614,即高于第一个,这是有道理的,但是当我提交给 Kaggle 时,0.78469低于第一个。

第三,我设置n_iter = 1000,它给了我α3并且 cv 分数是0.83951,即高于第二个,这是有道理的,但是当我提交给 Kaggle 时,0.77990低于第二个。

四、我设置n_iter = 5000,它给了我α4并且 cv 分数是0.84512,即高于第三个,这是有道理的,但是当我提交给 Kaggle 时,0.72249低于第三个。

这真是令人沮丧。该模型在交叉验证分数上越来越好,但在实际独立数据集上执行时,其性能越来越差。我是否以完全相反的方式解释 CV 分数?我看到一些论文提到,CV 分数可能过于乐观,无法推断出真实的考试分数。但是,即使这是真的,那么我认为我所有的 4 个模型的 CV 分数都应该对自己的真实测试分数持乐观态度,即顺序应该保持不变。但是当应用于真实的测试数据集时,顺序颠倒了。

我能想象的唯一原因是,测试数据集的分布与训练数据集不同。但是,如果真的是这样的话,那么我相信在当时的阳光下没有任何方法可以治愈这个问题。

4个回答

首先,一个务实的答案:不要忽视测试集来自与您用于训练和交叉验证的数据集不同的分布的可能性。您可能认为这不应该发生,但实际上它似乎确实发生了。

也就是说,让我们假设您的假设测试集来自与您的其余数据完全相同的分布。在这种情况下,如果您使用交叉验证来选择超参数,那么交叉验证可能会让您误以为哪个模型更好。

您可以使用交叉验证来 (a) 选择超参数,(b) 估计模型的准确度——但不能同时进行两者。

看来您正在使用交叉验证来选择最佳超参数:您为超参数尝试了许多不同的选择,对于每个选择,使用交叉验证估计该选择的准确性,然后选择最佳选择。当你这样做时,不能保证得到的准确性(具有最佳参数)将预测测试集的性能——它可能被高估了(由于过度拟合)。如果对 M1 的估计比对 M2 的估计更高,那么您可能会看到您所看到的。

如果您既想选择超参数又想估计准确度,我建议您有一个单独的保留验证集来估计准确度,或者使用嵌套交叉验证。请参阅https://stats.stackexchange.com/q/65128/2921http://scikit-learn.org/stable/auto_examples/model_selection/plot_nested_cross_validation_iris.html

交叉验证(v-fold 交叉验证)背后的理论已在许多论文中得到解决。在 2003-2007 年发表的一组论文中有一个证明。请参考: - oracle 选择器。2006 - 超级学习者 2007 - 预测中的超级学习者 2010 - 统一交叉验证 2003

我可以声称还是应该期望看到 M1 在新的测试数据集上仍会比 M2 表现更好?

是的你应该。当然在这样的条件下

  1. 测试数据来自与训练和验证数据相同的生成过程,并且
  2. 您在每组中都有足够的数据,以使统计波动不太可能发生。

该模型在交叉验证分数上越来越好,但在实际独立数据集上执行时,其性能越来越差。

我可以想到两个原因:

  1. 测试数据集确实不是以同样的方式生成的。因此,最好不要依赖您无权访问的 Kaggle 测试集。使用您拥有的数据。

  2. 您过度拟合,这意味着您没有正确执行交叉验证。确保参数的训练发生在训练数据上,同时,验证发生在您用于训练的数据上。比较训练损失和验证损失的直方图。训练损失应该始终小于验证损失。对测试数据的损失执行相同的操作以获得一致的图片。

最后注:可以预期的是,测试集的性能低于验证集的性能。这是因为模型是根据验证集选择的。所以它偏向于那个数据集。

有可能的。考虑一个简单的场景,模型比模型更好地M1学习了训练数据集的方差,因为它的参数得到了更好的调整。这意味着性能优于DM2M1DM2

但是当我们在测试集上测试它们时T,可能会M2表现得更好,因为M1可能会过拟合D,而M2没有。因此M1表现T比差M2

这可能是因为您在同一数据集而不是验证集上执行了交叉验证。如果您在同一组训练和验证,您可能会忽略它可能过度拟合的事实。因此,在不同的数据集上训练、验证和测试总是更好。所以流量应该是

  1. 在同一个训练集上训练不同的模型
  2. 在验证集验证
  3. 在验证集中选择表现最好的模型基础性能
  4. 用它来给你的测试集打分。