在文本分類問題當中,數據集打完標籤後,類別數量不均衡,這時候的測試集與訓練集應該如何製作?

在使用搜狗實驗室的新聞數據集時,打完標籤後的各類新聞數量如下

可以看到各個類別的新聞數量十分不均衡,在製作訓練集和測試集時,應該怎麼做?如果採用一刀切的方式只從每個類別當中抽取2000條數據製作,會覺得浪費了數據。那麼遇到這種情況時,應該如何抽取數據來製作數據集和測試集呢?


多分類任務中類別不均衡是非常常見的一個問題,但是差別多少才算分布不均勻呢?

這個沒有一個確定的衡量標準。根據我個人的經驗的話,不同類別數量差異超過一個數量級,我才會認為樣本類別分布不均勻,需要特別關注和調整。比如題主的截圖,最大的類別數是最小類別的三個數量集,差距非常大,觸犯了樣本類別分布不均的情況。

針對樣本分布不均勻,可以從以下幾個方面來多加關注和嘗試:

  1. sample數據:

當樣本類別分布不均勻的時候,什麼都不管還是直接將數據shuffle,隨機切分訓練/驗證/測試集,顯然是不太合理的。常用的有簡單欠採樣和過採樣的方法。

欠採樣:如題主,就這桶的最短板「一刀切」,每個類別sample最小值239,這樣就保證了數據分布絕對均勻,但是造成了嚴重的數據浪費。

過採樣:以最高板為標準,重複拼接短板(重複抽樣類別量小的數據)。這樣數據重複使用,肯定不會造成浪費了吧。但是問題來了,對數量少的類別(如總共只有239個樣本),強行將每個樣本重複10^3遍,模型訓練一個epoch的時候,對這類數據重複學習了10^3次,並且數據量本身就非常小,只有239個,極大可能造成在這些類別上過擬合

兩者之間更智能的方法:

簡單講一下工作中親測有效的方法,也是在multi-task learning中常用的sample方式。使用multinomial distribution,對不均衡的數據分布做平滑。

pi為原始數據分布中第i類數據出現的概率,qi為平滑處理後抽取第i類數據的概率。通過這個分布平滑抽樣,抽樣結果不會改變原始的各類別數據量大小的序關係,但是對類別數量過大的類數據量會相對減少,對類別數量過小的類數據量會相對增加。減少過擬合的可能性,也沒有過度浪費數據。

參見論文:https://arxiv.org/pdf/1901.07291.pdf

2. 加權的損失函數

對於樣本數量少的類別,可以考慮加大對該類別誤判的懲罰,實質上時增加這類樣本的權重,修正模型因為數量少而關注少的問題。

3. 評估指標

不要一股腦的只看所有類別整合的評估指標如ACC(當類別分布不均勻的時候會有極度的欺騙性)。

不妨細緻的對比驗證集和測試集的混淆矩陣,計算各類別的precision和recall,通過結果發現問題,指導你後續應該怎麼優化。

採樣方法、加權損失,個人認為還是治標不治本。在使用神經網路等需要大量數據支撐的模型演算法時,該增加數據量還是得跟上,不管通過人工標註,還是使用其他一些數據增強的方法。


類別不平衡學習大致有三種策略:一,欠採樣,針對數量過多的樣例。二,過採樣,針對數量較少的樣例。三,閾值移動,就是對閾值進行調整。直接基於原始數據訓練,進行預測時,用樣例的真實觀測幾率來修正閾值。


機器學習任務的目標,是找出使得 [公式] 成立的函數 [公式] 。大部分機器學習演算法都有一個(隱含)假設,即訓練集和測試集(驗證集)遵循相同的統計分布(獨立同分布)。這既意味著訓練集和測試集的輸入樣本( [公式] )滿足同樣的分布,又意味著二者的的輸出樣本( [公式] )滿足同樣的分布。以分類問題為例,如果我們已經獲得了一個標註好的數據集,那麼只要隨機採樣,獲得的兩個沒有交集的樣本,就可以作為理想的訓練集和測試集,因為這兩個樣本是獨立同分布的。

然而,在現實生活中,類別不平衡問題廣泛存在。許多針對類別不平衡問題提出的解決方案主要關注這種情形:訓練集的類別嚴重偏離平衡(不平衡比 [公式] ),但測試集(驗證集)的類別是比較平衡的( [公式] )。解決方案主要有:

  1. 過採樣(隨機採樣、SMOTE、ADASYN等)
  2. 降採樣
  3. 過採樣與降採樣結合(SMOTEENN、SMOTETomek)等。

在這些思想或者演算法的基礎上,有許多人提出了各種自帶採樣器的集成學習方法,比如包含採樣的隨機森林(Random Forest)、提升學習(Boosting)方法等。採樣可以說是處理類別不平衡問題的第一種思路。關於這部分,python包imbalanced-learn做了很好的總結,可以直接使用它的模塊,或者參考模塊的寫法。

第二種思路是修改權重(re-weighting)。簡言之,如果在訓練時降低多數類樣本對損失函數的貢獻,使其總貢獻與少數類樣本對損失函數的總貢獻均衡,那麼學習器對多數類的偏重就會減輕。比如,sklearn中的隨機森林等演算法,可以手動設置"class_weight"參數,一般來說將class_weight設置成與類別比成反比即可,多類的情況同理,具體可以參考文檔。

有的答主提到了深度學習中的「focal loss」損失函數,它和GHM等損失函數也都是通過修改權重來起作用的。與簡單的「class weight」不同,「focal loss」和GHM將類別不平衡問題的難點歸結為分類「硬度」(hardness)問題,即造成困難的主要是少數難分類的樣本,而非大多數易分類的樣本。因此,如果將某些難分樣本的損失函數權重提高,將大多數易分類樣本的權重降低,那麼就能提升整體的學習效果。

以上兩種思路是數據和演算法層面的考量。第三點也有答主指出來了,就是使用比accuracy、F1-score等更合適的評價標準。Accuracy、F1-score並未考慮類別比例,在類別不平衡情況下沒有太高的參考價值。我個人傾向於使用Matthews correlation coefficient (MCC) ,因為它在數學上考慮了類別比例。下面這篇文章對MCC的重要性有比較詳細的檢驗和介紹:【Chicco, D., Jurman, G. The advantages of the Matthews correlation coefficient (MCC) over F1 score and accuracy in binary classification evaluation.BMC Genomics21,6 (2020). https://doi.org/10.1186/s12864-019-6413-7】

https://bmcgenomics.biomedcentral.com/articles/10.1186/s12864-019-6413-7?

bmcgenomics.biomedcentral.com

當然,類別不平衡問題是一個深坑,很多出色的演算法遇到它時也風光不再。不過有時候,你可能會發現類別不平衡並未對你的任務帶來什麼困難(考慮「硬度」,或者特徵空間中的類別重疊程度)。我覺得目前還沒有通用的/好用的針對類別不平衡問題的方法,但是現有的演算法,結合你自己對於數據的理解,多多少少可以減輕類別不平衡帶來的影響。(有空再填)


這是我的步驟:

如果數據集不平衡,改用F1分數作為評判標準,然後啟用演算法的懲罰機制,例如sklearn里的各個機器學習演算法都有一個參數叫class weight,把它設置成balanced,樣本數量少的種類權重就會變大,以這樣一個方式訓練所有模型。

然後還沒完。

根據你的case,有些種類的樣本數量很少,只有幾百,所以可以用過採樣演算法比如smote,這屬於人為地製造一些數據直到達到樣本平衡。此時再訓練一遍所有模型。

比較前後2次的訓練結果來得出最終模型,根據我的以往項目經驗,第一次選出的最優模型在使用過採樣演算法之後依然是最優的。

我個人其實很懷疑這些人為製造數據的演算法,所以在我這裡我只是當個驗證而已。

另外模型的精確度,F1分數之類的只有在選擇模型上有參考價值,一旦選出,實際效果其實很難判斷,最後選擇出的模型也只能表明,這個模型可能最接近現實。


說句實話吧,不平衡數據咋搞都很難。但實戰經驗告訴我,不平衡數據根本不用處理。如果不死心,可以試試把多數類做欠採樣,搞成和少數類差不多的樣本量,然後做個融合建模。如有興趣,可以看看這個。

https://github.com/yzkang/My-Data-Competition-Experience?

github.com


推薦閱讀:
相关文章