繁体   English   中英

k-fold分层交叉验证与不平衡类

[英]k-fold stratified cross-validation with imbalanced classes

我有4个类的数据,我正在尝试构建一个分类器。 我有一个类的〜1000个向量,另一个有~10 ^ 4,第三个为~10 ^ 5,第四个为~10 ^ 6。 我希望使用交叉验证,所以我查看了scikit-learn文档

我的第一次尝试是使用StratifiedShuffleSplit但是这给了每个类相同的百分比,使得类仍然严重失衡。

有没有办法进行交叉验证,但是在训练和测试集中平衡了类?


作为旁注,我无法弄清楚StratifiedShuffleSplitStratifiedKFold之间的区别。 描述与我非常相似。

我的第一次尝试是使用StratifiedShuffleSplit但是这给了每个类相同的百分比,使得类仍然严重失衡。

我觉得你会混淆分层策略会做什么,但你需要显示你的代码和结果,以确定发生了什么(与原始集合中的百分比相同的百分比,或相同返回的火车/测试集中的百分比?第一个是它应该如何)。

作为旁注,我无法弄清楚StratifiedShuffleSplit和StratifiedKFold之间的区别。 描述与我非常相似。

其中一个绝对应该工作。 对第一个的描述肯定有点令人困惑,但这就是他们所做的。

StratifiedShuffleSplit

提供列车/测试索引以在列车测试集中分割数据。

这意味着它将您的数据拆分为火车和测试集。 分层部分意味着在这种分裂中将保持百分比 因此,如果10%的数据属于1级, 90%属于2级, 这将确保10%的列车将在1级, 90%将在2级 对于测试集也是如此。

你的帖子听起来好像你想要测试集中每个类的50% 这不是分层所做的,分层保持了原始的百分比。 你应该维护它们,因为否则你会给自己一个关于你的分类器性能的不相关的想法:谁在乎它对50/50分割的分类,在实践中你会看到10/90分裂?

StratifiedKFold

此交叉验证对象是KFold的变体,可返回分层折叠。 通过保留每个类别的样本百分比来进行折叠。

参见k-fold交叉验证 没有分层,它只是将您的数据分成k折叠。 然后,每个折叠1 <= i <= k一次用作测试集,而其他折叠用于训练。 结果平均到最后。 它类似于运行ShuffleSplit k次。

分层将确保整个数据中每个类别的百分比在每个单独的折叠中相同(或非常接近)。


有很多文献涉及不平衡的阶级。 一些简单易用的方法涉及使用类权重和分析ROC曲线。 我建议以下资源为此起点:

  1. 使用类权重的scikit-learn示例
  2. 关于为不平衡数据实现神经网络的问题
  3. 这个stats.stackexchange问​​题有更深入的答案

K-Fold CV

K-Fold CV通过将数据随机分区为k (相当)相等的分区来工作。 如果您的数据在[0,1,0,1,0,1,0,1,0,1]等类之间均衡平衡,则随机抽样(或不进行替换)将为您提供大约等于01样本大小。

但是,如果您的数据更像是[0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0]其中一个类代表数据,没有加权采样的k-fold cv会给你错误的结果。

如果你使用普通的k-fold CV,而不是从均匀采样中调整采样权重,那么你就可以获得类似的东西

## k-fold CV
k = 5
splits = np.array_split(y, k)
for i in range(k):
    print(np.mean(splits[i]))

 [array([0, 0, 0, 0, 0, 0, 0]),
 array([0, 0, 0, 0, 0, 0, 0]),
 array([0, 0, 0, 0, 0, 0]),
 array([0, 0, 0, 0, 0, 0]),
 array([0, 1, 1, 1, 1, 1])]

哪里有明显的分裂,没有两个类的有用表示。

k倍CV的点是在所有数据子集上训练/测试模型,而在每次试验中留下1个子集并训练k-1个子集。

在这种情况下,您希望使用split by strata。 在上面的数据集中,有27 0s和5 1s 如果你想计算k = 5 CV,将1的分层分成5个子集是不合理的。 更好的解决方案是将其分成k <5个子集,例如2. 0s的分层可以保持k = 5个分裂,因为它更大。 然后在训练时,您将从数据集中获得2 x 5的简单产品。 这是一些代码来说明

from itertools import product

for strata, iterable in groupby(y):
    data = np.array(list(iterable))
    if strata == 0:
        zeros = np.array_split(data, 5)
    else:
        ones = np.array_split(data, 2)


cv_splits = list(product(zeros, ones))
print(cv_splits)

m = len(cv_splits)
for i in range(2):
    for j in range(5):
        data = np.concatenate((ones[-i+1], zeros[-j+1]))
        print("Leave out ONES split {}, and Leave out ZEROS split {}".format(i,j))
        print("train on: ", data)
        print("test on: ", np.concatenate((ones[i], zeros[j])))



Leave out ONES split 0, and Leave out ZEROS split 0
train on:  [1 1 0 0 0 0 0 0]
test on:  [1 1 1 0 0 0 0 0 0]
Leave out ONES split 0, and Leave out ZEROS split 1
train on:  [1 1 0 0 0 0 0 0]
...
Leave out ONES split 1, and Leave out ZEROS split 4
train on:  [1 1 1 0 0 0 0 0]
test on:  [1 1 0 0 0 0 0]

此方法可以完成将数据拆分为分区,其中最终省略所有分区以进行测试。 应该注意的是,并非所有统计学习方法都允许加权,因此调整CV等方法对于考虑采样比例至关重要。

  • 参考文献:James,G.,Witten,D.,Hastie,T。,&Tibshirani,R。(2013)。 统计学习简介:在R中的应用程序

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM