为什么要使用分层交叉验证?为什么这不会损害与差异相关的利益?

机器算法验证 交叉验证 重采样 分层
2022-02-12 17:52:23

有人告诉我,使用分层交叉验证是有益的,尤其是在响应类不平衡时。如果交叉验证的一个目的是帮助解释我们原始训练数据样本的随机性,那么除非您确定原始训练集具有代表性的类分布,否则使每个折叠具有相同的类分布肯定会对此产生影响。

我的逻辑有问题吗?

编辑 我对这种方法是否会损害 CV 的优点感兴趣。如果您有一个小样本/非常不平衡的类/两者,我可以明白为什么有必要避免在折叠中没有一个小类的代表。

交叉验证研究中的苹果对苹果:分类器性能测量中的陷阱很好地提出了分层的案例,但所有论点似乎都相当于“分层提供了保障和更多的一致性”,但只要足够多,就不需要保障数据。

答案很简单:“我们出于必要而使用它,因为我们很少有足够的数据。” ?

2个回答

Bootstrapping 旨在模拟从总体中抽取新样本的效果,而不是寻求确保不同的测试集(N 次抽样后的 N 次替换后的残差)。

RxK-fold 交叉验证确保 K 个不同的测试折叠,但随后针对不同的随机分区重复 R 次,以允许 K-CV 保持独立性假设,但这会随着重复而丢失。

分层交叉验证违反了在计算统计数据之前不应该查看测试标签的原则,但这通常被认为是无害的,因为唯一的效果是平衡折叠,但它确实会导致多样性的损失(不必要的方差损失)。它比 Boostrap 的想法更进一步,即构建一个类似于您从整个人群中自然抽取的样本。可以说,分层很重要的主要原因是解决分类算法中的缺陷,因为它们很容易因类的过度或不足而产生偏差。使用平衡技术(通过选择或加权)或优化机会正确度量(Kappa 或最好是知情度)的算法受此影响较小,尽管即使这样的算法也可以

强制每个折叠至少有每个类的 m 个实例,对于一些小的 m,是分层的替代方案,适用于 Bootstrapping 和 CV。它确实有一个平滑偏差,使得折叠往往比预期的更平衡。

重新集成和多样性:如果将在训练折叠上学习的分类器用于融合而不仅仅是估计泛化误差,则与 Bootstrap、强制 Bootstrap 相比,CV、分层 Bootstrap 和分层 CV 的刚性增加会导致多样性丧失和潜在的弹性并强制投简历。

也许你可以这样想。假设您有一个数据集,其中有 100 个样本,“A”类中有 90 个,“B”类中有 10 个。在这种非常不平衡的设计中,如果您进行正常的随机分组,您最终可能会在“B”类的极少数(或什至没有!)上构建模型。如果您正在构建一个模型,该模型是在其他类别中很少甚至没有的数据上进行训练的,您如何期望它能够有效地预测稀有组?分层交叉验证允许随机化,但也确保这些不平衡的数据集具有两个类中的一些。

为了消除对使用具有更“平衡”数据集的分层 CV 的担忧,让我们看一个使用 R 代码的示例。

require(mlbench)
require(caret)
require(cvTools)

# using the Sonar dataset (208 samples)
data(Sonar)

# see the distribution of classes are very well balanced
prop.table(table(Sonar$Class))

> prop.table(table(Sonar$Class))

M         R 
0.5336538 0.4663462 

# stratified
# set seed for consistency
# caret::createFolds does stratified folds by default
set.seed(123)
strat <- createFolds(Sonar$Class, k=10)

# non-stratified using cvTools
set.seed(123)
folds <- cvFolds(nrow(Sonar), K=10, type="random")
df <- data.frame(fold = folds$which, index = folds$subsets)
non_strat <- lapply(split(df, df$fold), FUN=function(x) x$index)

# calculate the average class distribution of the folds
strat_dist <- colMeans(do.call("rbind", lapply(strat, FUN = function(x) prop.table(table(Sonar$Class[x])))))
    non_strat_dist <- colMeans(do.call("rbind", lapply(non_strat, FUN = function(x) prop.table(table(Sonar$Class[x])))))
strat_dist
> strat_dist
M         R 
0.5338312 0.4661688 
non_strat_dist
> non_strat_dist
M         R 
0.5328571 0.4671429 

如您所见,在一个平衡良好的数据集中,褶皱将随机出现相似的分布。因此,在这些情况下,分层 CV 只是一种保证措施。但是,要解决差异,您需要查看每个折叠的分布。在某些情况下(甚至从 50-50 开始),您可能会随机产生 30-70 的折叠(您可以运行上面的代码并看到这实际上发生了!)。这可能会导致模型性能更差,因为它没有足够的一类来准确预测它,从而增加了整体 CV 方差。当您拥有“有限”样本时,这显然更重要,因为您更有可能在分布上有非常极端的差异。

现在对于非常大的数据集,可能不需要分层,因为折叠将足够大,仍然可能至少包含很大比例的“稀有”类。但是,如果您的样本不平衡,无论您有多少数据,我个人认为 ,实际上没有计算损失,也没有真正的理由放弃分层。