【问题标题】:k-fold stratified cross-validation with imbalanced classes具有不平衡类的 k 折分层交叉验证
【发布时间】:2015-12-13 10:38:16
【问题描述】:

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

我的第一次尝试是使用StratifiedShuffleSplit,但这会为每个班级提供相同的百分比,从而使班级仍然严重不平衡。

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


附带说明,我无法计算出 StratifiedShuffleSplitStratifiedKFold 之间的区别。描述看起来和我很相似。

【问题讨论】:

  • 请显示一些代码

标签: python machine-learning scikit-learn


【解决方案1】:

我的第一次尝试是使用 StratifiedShuffleSplit,但这会为每个班级提供相同的百分比,从而使班级仍然严重不平衡。

我感觉您对分层策略的作用感到困惑,但您需要展示您的代码和结果来确定发生了什么(与原始集合中的百分比相同,还是返回的训练/测试集中的相同百分比?第一个是它应该是的)。

附带说明,我无法弄清楚 StratifiedShuffleSplit 和 StratifiedKFold 之间的区别。描述看起来和我很相似。

其中一个肯定可以工作。第一个的描述肯定有点令人困惑,但这就是它们的作用。

StratifiedShuffleSplit

提供训练/测试索引以拆分训练测试集中的数据。

这意味着它将您的数据拆分为训练集和测试集。分层部分意味着将在此拆分中保持百分比。因此,如果您的数据中的 10% 属于 1 类,而 90% 属于 2 类,这将确保您的火车组的 10% 属于 1 类,而 90% 将属于 2 类。测试集也一样。

您的帖子听起来像是您想要测试集中每个班级的50%。这不是分层所做的,分层保持原始百分比。你应该维护它们,否则你会给自己一个与分类器性能无关的想法:谁在乎它对 50/50 拆分的分类效果如何,实际上你会看到 10/90 拆分?

分层KFold

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

k-fold cross validation。如果没有分层,它只会将您的数据拆分为k 折叠。然后,每个折叠1 <= i <= k 使用一次作为测试集,而其他折叠用于训练。结果最后取平均值。类似于运行ShuffleSplitk 次。

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


有很多关于不平衡类的文献。一些简单易用的方法包括使用类权重和分析 ROC 曲线。我建议以下资源作为起点:

  1. A scikit-learn example of using class weights
  2. A quora question about implementing neural networks for imbalanced data
  3. This stats.stackexchange question with more in-depth answers

【讨论】:

  • 感谢您的回答。你说得对,我对分层的含义感到困惑。保持百分比相同的问题在于,分类器会错误地分类第 1 类中的大部分(具有 1000 个向量),而其余的大部分都是正确的。我希望分类器尝试使每个类的错误分类百分比大致相同。为此,从每个类中选择相同数量的向量是有意义的。有没有办法做到这一点?
  • @eleanora 真的,你不想那样做。它最终无济于事,在最坏的情况下,它只会给你一种虚假的安全感。如果您的班级不平衡,请查看班级权重:scikit-learn.org/stable/auto_examples/svm/…quora.com/… ; ROC 曲线:stats.stackexchange.com/questions/6067/…
  • @eleanora 如果您坚持这样做,这非常简单:为您的训练集确定大小 x,然后选择第 1 类的 x / 4,与第 2、3、4 类相同. 但是,真的,这是一个错误的事情!
  • 再次感谢您。我正在使用随机森林,我将研究使用 class_weight 。我读了stackoverflow.com/questions/8704681/…,这似乎与它确实建议减少课程不平衡的地方密切相关。我不确定如何使用 ROC 曲线来解决多类问题。
  • @eleanora 这有点不同,因为那里的课程比你自己的课程更不平衡,答案只是建议减少一点。不过,我认为还有更好的方法。如果您查看 stats SE 问题,您会发现按照您的建议去做是可以接受的,但前提是您要小心地以不同方式解释结果。
【解决方案2】:

K 折 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-fold CV 的重点是在所有数据子集上训练/测试模型,同时在每次试验中省略 1 个子集并在 k-1 个子集上进行训练。

在这种情况下,您可能希望使用按层拆分。在上面的数据集中,有27个0s和5个1s。如果您想计算 k=5 CV,将1 的层分成 5 个子集是不合理的。更好的解决方案是将其拆分为 k 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 中的应用。

【讨论】:

    猜你喜欢
    • 2021-12-26
    • 2021-10-08
    • 2016-01-15
    • 2013-05-03
    • 2017-01-11
    • 2021-02-17
    • 2012-05-11
    • 2018-07-26
    • 1970-01-01
    相关资源
    最近更新 更多