TLDR:
我使用 10-fold CV 评估了一个分类模型,在训练和测试折叠中存在数据泄漏。结果很好。然后我解决了数据泄漏,结果是垃圾。然后,我在一个独立的新数据集中测试了该模型,结果与使用数据泄漏执行的评估相似。
这是什么意思?我的数据泄露不相关吗?我可以信任我的模型评估并报告该性能吗?
扩大的视野:
我正在使用数据集 108326x125(观察 x 特征)开发一个二元分类模型,其类别不平衡约为 1:33(每 33 个负面观察有 1 个正面观察)。然而,这 108326 次观察仅来自 95 名受试者,这意味着每个受试者都有不止一次的观察。
最初,在模型训练和评估期间,我使用命令执行交叉验证(CV)(classes是一个包含每个观察类的列数组):
cross_validation = cvpartition(classes,'KFold',10,'Stratify',true);
并在我最感兴趣的指标(召回率和精度)方面获得了良好的表现。该模型是一个集成(增强树)。
但是,通过执行上述 CV 分区,我有数据泄漏,因为在给定的 CV 迭代中,来自同一受试者的观察结果可能同时在训练和测试集中。除了数据泄漏之外,我认为我的模型可能是过拟合的,因为每个树的最佳超参数集合中的最大叶子数约为 350,通常这个参数应该在 8 和 32 左右(为了避免每棵树成为强学习者,这可能会导致过度拟合)。
然后,我执行了一个不同的 CV 分区,按主题 ID 进行分区,从而解决了数据泄漏问题。但是,这样做时,训练集和测试集中的类分布可能会变得非常不同(因为大约 30 名受试者没有正面观察,甚至在极端情况下,某些测试折叠可能最终有 0 正面观察),这会影响我对模型性能的评价。为了缓解这种情况,我重复了 5x10-CV。
使用这个分区,我测试了几种不同的模型类型(包括与具有数据泄漏的模型和超参数完全相同的模型),例如 MATLAB 的 fitcensemble 和 KNN 以及 Python 的 XGBoost(并在所有这些模型中进行了超参数优化),不管怎样我所做的,我根本无法通过这种方法达到可接受的性能。因此,我的第一个问题是:
1. 这种分区是否有问题可能会影响我的模型评估?(见下面的代码)
2. 你有什么建议来改进这个 CV 分区吗?
最后,为了确认我最初的模型评估(分区中存在数据泄漏)误导了我,我在一个独立的新数据集(但是小得多)中测试了模型并且性能很好(类似于通过 CV 分区获得的模型) !!
这是什么意思?我的数据泄露不相关吗?我可以信任我的模型评估并报告该性能吗?
先感谢您!
*基于主题的分区代码
% Randomize subjects list order to introduce randomization to the partition process
data_name_list = data_name_list(randperm(length(data_name_list)));
% Get array containing the corresponding fold of each subject ('histcounts' splits subjects as
% uniformly as possible when using BinWidth like this)
[~,~,fold_of_subject] = histcounts(1:length(data_name_list), 'BinWidth', length(data_name_list)/num_folds);```