为什么 10 折交叉验证的准确度得分比使用 sklearn 的 90-10 train_test_split 更差?

How is it that the accuracy score for 10-fold cross validation is worst than for a 90-10 train_test_split using sklearn?

该任务是通过神经网络进行的二进制 class化。数据存在于字典中,其中包含每个条目的复合名称(作为键)和标签(0 或 1,作为向量值中的第三个元素)。第一和第二个元素是复合名称的两部分,后面用来提取对应的特征。

在这两种情况下,字典都被转换成两个数组,目的是对大多数 class(存在于 66% 的数据中)进行平衡欠采样:

data_for_sampling = np.asarray([key for key in list(data.keys())])
labels_for_sampling = [element[2] for element in list(data.values())]

sampler = RandomUnderSampler(sampling_strategy = 'majority')
data_sampled, label_sampled = sampler.fit_resample(data_for_sampling.reshape(-1, 1), labels_for_sampling)

然后重采样的名称和标签数组用于通过 Kfold 方法创建训练集和测试集:

kfolder = KFold(n_splits = 10, shuffle = True)
kfolder.get_n_splits(data_sampled)

for train_index, test_index in kfolder.split(data_sampled):

        data_train, data_test = data_sampled[train_index], data_sampled[test_index]

或train_test_split方法:

data_train, data_test, label_train, label_test = train_test_split(data_sampled, label_sampled, test_size = 0.1, shuffle = True)

最后,data_train 和 data_test 中的名称用于从原始词典中重新提取相关条目(按键),然后用于收集这些条目的特征.就我而言,10 倍集的单个拆分应该提供与 90-10 train_test_split 相似的训练测试数据分布,这在训练期间似乎是正确的,两个训练集都会产生结果仅经过一个时期后,准确度约为 0.82,运行 与 model.fit() 分开。然而,当在所述纪元之后在测试集上使用 model.evaluate() 评估相应模型时,来自 train_test_split 的集给出的分数约为 0.86,而来自 Kfold 的集为~0.72。我做了很多测试,看看它是否只是一个不好的随机种子,它不受限制,但结果保持不变。这些集合还具有正确平衡的标签分布和看似经过精心打乱的条目。

根据数据中的噪声量和数据集的大小,这可能是预期的行为,因为样本数据的分数会偏离这个量。不能保证一次拆分与任何其他拆分一样,这就是为什么您首先有 10 个,然后对所有结果进行平均。

你应该相信最普遍的是不是任何给定的分割(无论它来自 10 折之一还是 train_test_split()),而是什么更值得信赖的是所有 N 次折叠的平均结果

深入挖掘数据可以揭示是否有某种原因导致一个或多个拆分与另一个拆分如此大的偏差。例如,您的数据中可能存在某些特征(例如“样本收集日期”和收集方法每个月都在变化),这使得数据以一种有偏见的方式彼此不同。如果是这种情况,您应该使用分层测试拆分(也在您的 CV 中)(参见 scikit-learn documentation on that),这样您可以获得更公正的数据分组。

事实证明,问题源于多种来源:

虽然 train_test_split() 方法中的 shuffle = True 首先正确地打乱提供的数据,然后将其拆分为所需的部分,但 Kfold 方法中的 shuffle = True 只会导致随机构建的折叠,但是 折叠内的数据保持有序

由于 post,文档指出了这一点: https://github.com/scikit-learn/scikit-learn/issues/16068

现在,在学习过程中,我的自定义训练函数再次对训练数据应用混洗,只是为了确定,但它不会混洗测试数据。此外,model.evaluate() 默认为 batch_size = 32,如果没有给出参数,这与有序的测试数据配对会导致验证准确性的差异。测试数据确实存在缺陷,因为它包含大部分“难以预测”的条目,这些条目由于排序而聚集在一起,似乎拖累了结果的平均准确性。正如 TC Arlen 所指出的那样,给定所有 N 次折叠的完整 运行,最终可能确实给出了更精确的估计,但我预计仅一次折叠后就会得到更接近的结果,这导致了发现这个问题。