簡體   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