分類問題中,當不同類別的樣本量差異很大,即類分佈不平衡時,很容易影響分類結果。因此,需要進行對預測概率進行校正。
sklearn的做法是加權,加權就要涉及到class_weight和sample_weight,當不設置該參數時,默認所有類別的權值爲1。
類型權重 class_weight
字典類型,將類索引映射到權重值。對訓練集裏的每個類別加權,作用於損失函數(僅在訓練過程中)。從而使模型更加關注樣本數量少的類別。如果某類別的樣本數多,那麼它的權重就低,反之則權重就高.
應用場景:
第一種是誤分類的代價很高。比如對合法用戶和非法用戶進行分類,將非法用戶分類爲合法用戶的代價很高,我們寧願將合法用戶分類爲非法用戶,這時可以人工再甄別,但是卻不願將非法用戶分類爲合法用戶。這時,我們可以適當提高非法用戶的權重class_weight={0:0.9, 1:0.1}。
第二種是樣本是高度失衡的,比如我們有合法用戶和非法用戶的二元樣本數據10000條,裏面合法用戶有9995條,非法用戶只有5條,如果我們不考慮權重,則我們可以將所有的測試集都預測爲合法用戶,這樣預測準確率理論上有99.95%,但是卻沒有任何意義。這時,我們可以選擇balanced(scikit-learn 邏輯迴歸類庫使用小結),讓類庫自動提高非法用戶樣本的權重。
參數設置
那麼應該如何設置class_weight呢?
- 通過字典形式傳入權重參數,如二分類問題,class_weight={0:0.9, 1:0.1}
- 設置class_weight = 'balanced’
此時,會自動調用from sklearn.utils.class_weight import compute_class_weight計算權重,平衡輸入樣本中各類別之間的權重。其計算公式爲:
import numpy as np
y = [0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2] #標籤值,一共16個樣本
a = np.bincount(y) # array([8, 6, 2], dtype=int64) 計算每個類別的樣本數量
aa = 1/a #倒數 array([0.125 , 0.16666667, 0.5 ])
print(aa)
from sklearn.utils.class_weight import compute_class_weight
class_weight = 'balanced'
classes = np.array([0, 1, 2]) #標籤類別
weight = compute_class_weight(class_weight, classes, y)
print(weight) # [0.66666667 0.88888889 2.66666667]
print(0.66666667*8) #5.33333336
print(0.88888889*6) #5.33333334
print(2.66666667*2) #5.33333334
# 這三個值非常接近
# 'balanced'計算出來的結果很均衡,使得懲罰項和樣本量對應
這種方式在原始的損失函數的基礎上乘以對應的sample_weight來計算最終的損失。這樣計算而來的損失函數不會因爲樣本不平衡而被“推向”樣本量偏少的類別中
樣本權重 sample_weight
numpy權重數組。對每個樣本加權(僅在訓練過程中),思路和類別權重類似,即樣本數多的類別樣本權重低,反之樣本權重高
應用場景:
樣本不平衡,導致樣本不是總體樣本的無偏估計,從而可能導致我們的模型預測能力下降。遇到這種情況,我們可以通過調節樣本權重來嘗試解決這個問題。調節樣本權重的方法有兩種,第一種是在class_weight使用balanced。第二種是在調用fit函數時,通過sample_weight來自己調節每個樣本權重。
注意事項:
-
在sklearn中的邏輯迴歸時,如果上面兩種方法都用到了,那麼樣本的真正權重是class_weight * sample_weight.
原理:樣本或類別的權重在訓練模型最終通過損失函數實現(以邏輯迴歸爲例):
算法會把每個樣本的訓練損失乘以它的權重class_weight*sample_weight,損失函數爲:其中,
應用:做受衆選擇(人羣擴展、人羣定向)模型,若種子包括目標商品轉化和行爲用戶(購買較少,加入線上加購、收藏作爲正樣本),可考慮加大轉化用戶的樣本權重。
-
如果僅僅是類不平衡,則使用class_weight;
如果類內樣本之間還不平衡,則使用sample_weights。 -
如果class_weight選擇balanced,那麼類庫會根據訓練樣本量來計算權重。某種類型樣本量越多,則權重越低,樣本量越少,則權重越高。