日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[机器学习] XGBoost 样本不平衡问题

發(fā)布時間:2023/12/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [机器学习] XGBoost 样本不平衡问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一 樣本不平衡

何謂樣本不平衡——簡單來說就是數(shù)據(jù)集中負(fù)樣本的數(shù)量遠(yuǎn)遠(yuǎn)大于正樣本的數(shù)量。在這個情況下,模型就會傾向于把樣本預(yù)測為負(fù)樣本,因為這是最便捷的降低損失、提高模型準(zhǔn)確率的方法。例如:有一個正樣本數(shù)量為1,負(fù)樣本數(shù)量為99的數(shù)據(jù)集,模型就算無腦地把全部樣本預(yù)測為負(fù)樣本也能達(dá)到99%的準(zhǔn)確度,試想有這么一個分類器,每次我們把數(shù)據(jù)喂‘給它時,在不調(diào)整閾值的情況下,它都傾向于把測試集的樣本預(yù)測為負(fù)樣本,你覺得這樣的分類器還會是一個好的分類器嗎?

在對不平衡數(shù)據(jù)進(jìn)行訓(xùn)練時,通常會考慮一下怎么處理不平衡數(shù)據(jù)能使訓(xùn)練出來的結(jié)果較好。

在用xgboost訓(xùn)練二分類模型時,除了直接使用過采樣和下采樣,xgboost接口還提供一些處理不平衡數(shù)據(jù)的方法,有scale_pos_weight參數(shù)的設(shè)置,還有給樣本賦予一定的權(quán)重。接下來讓我們仔細(xì)看一下吧~

參數(shù)scale_pos_weight:

XGBoost中存在著調(diào)節(jié)樣本不平衡的參數(shù)scale_pos_weight,通常我們在參數(shù)中輸入的是負(fù)樣本量與正樣本量之比

底層原理:通過scale_pos_weight改變了正負(fù)樣本的權(quán)重,進(jìn)而改變了正負(fù)樣本損失函數(shù)的大小,最終改變了樣本的概率預(yù)測值 wi。

For common cases such as ads clickthrough log, the dataset is extremely imbalanced. This can affect the training of xgboost model, and there are two ways to improve it.If you care only about the ranking order (AUC) of your predictionBalance the positive and negative weights, via scale_pos_weightUse AUC for evaluationIf you care about predicting the right probabilityIn such a case, you cannot re-balance the datasetIn such a case, set parameter max_delta_step to a finite number (say 1) will help convergence

官方的解釋是這樣的,scale_pos_weight 可以設(shè)置為數(shù)據(jù)中負(fù)樣本數(shù)量/正樣本數(shù)量

if (info.labels[i] == 1.0f) w *= param_.scale_pos_weight

scale_pos_weight 是用來調(diào)節(jié)正負(fù)樣本不均衡問題的,用助于樣本不平衡時訓(xùn)練的收斂。

scale_pos_weight = 負(fù)樣本總數(shù)/正樣本總數(shù) 。若訓(xùn)練負(fù)樣本總數(shù)是500 ,正樣本總數(shù)100,那么設(shè)置 scale_pos_weigh為 5 。

?

常見的情況比如廣告點擊日志,數(shù)據(jù)集是極其不平衡的,導(dǎo)致訓(xùn)練的xgboost模型受到影響,有兩種方法可以改善:

1)? 如果僅僅關(guān)注預(yù)測問題的AUC指標(biāo),那么你可以調(diào)節(jié) scale_pos_weight參數(shù)來幫助訓(xùn)練數(shù)據(jù)不平衡帶來的收斂問題 。

2)如果關(guān)注預(yù)測概率的準(zhǔn)確性問題,那么你就不能調(diào)節(jié)scale_pos_weight參數(shù)來改變樣本權(quán)重的方法幫助收斂,可通過設(shè)置參數(shù) max_delta_step 為一個有限的值來幫助收斂 。


如何你僅僅關(guān)注預(yù)測問題的排序或者AUC指標(biāo),那么你盡管調(diào)節(jié)此參數(shù)。如果你希望得到真正的預(yù)測概率則不能夠通過此參數(shù)來平衡樣本。什么意思呢,讓我們來舉個例子:加入我們現(xiàn)在需要通過體重來預(yù)測男女,有三個人體重分別為50kg、60kg、70kg。假設(shè)他們是男生的真正概率是:0.4、0.6、0.8。那么好,我現(xiàn)在模型預(yù)測出的概率為:0.7、0.8、0.9。如果講預(yù)測概率的話,顯然模型效果很差,但是我們預(yù)測的男生概率的排序以及 ROU 曲線(包括對應(yīng) AUC 值)都不會改變。

?關(guān)于scale_pos_weight ,在xgboost里邊的源碼是

bst_float w = _is_null_weight ? 1.0f : _weights[_idx];bst_float label = _labels[_idx];if (label == 1.0f) {w *= _scale_pos_weight;}if (!Loss::CheckLabel(label)) {// If there is an incorrect label, the host code will know._additional_input[0] = 0;}# 改變了損失函數(shù),即改變了損失函數(shù)的一階導(dǎo)和二階導(dǎo)大小,落到每個葉結(jié)點的概率預(yù)測值也隨之改變。_out_gpair[_idx] = GradientPair(Loss::FirstOrderGradient(p, label) * w,Loss::SecondOrderGradient(p, label) * w);},# 見源碼 src/objective/regression_obj.cu

從源代碼也可以看出,scale_pos_weight其實就是改變樣本weight,也就是和在DMatrix里邊設(shè)置每個樣本的weight是一樣的。

在DMatrix里邊設(shè)置每個樣本的weight 是怎樣改變訓(xùn)練過程的呢,其實是改變訓(xùn)練的損失函數(shù),源代碼里的代碼如下,可以看到對不同的樣本賦予不同的權(quán)重實際上是影響了該樣本在訓(xùn)練過程中貢獻(xiàn)的損失,進(jìn)而改變了一階導(dǎo)和二階導(dǎo)。

其中?是損失函數(shù)關(guān)于上一棵樹的預(yù)測值的的一階導(dǎo),?是損失函數(shù)關(guān)于上一棵樹的預(yù)測值的二階導(dǎo),當(dāng)正樣本的損失函數(shù)發(fā)生改變,相應(yīng)的葉子節(jié)點的預(yù)測值也會發(fā)生改變。

本質(zhì)上說,scale_pos_weight參數(shù)也是通過調(diào)節(jié)樣本的預(yù)測概率值來改變預(yù)測結(jié)果,當(dāng)我們需要提高模型的評估標(biāo)準(zhǔn) ——如 auc、召回率recall的大小等,可以通過調(diào)整scale_pos_weight參數(shù)達(dá)到我們的目的;但是,假如需要確切了解每個樣本為正樣本的可能性大小時,不宜使用scale_pos_weight參數(shù)。

使用官方數(shù)據(jù)例子:agaricus.txt.train 與 agaricus.txt.test

系統(tǒng)Default,設(shè)置scale_pos_weight = 1。觀察訓(xùn)練過程

print("\n--------- scale_pos_weight = 1 -----------") dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train') dtest = xgb.DMatrix('../demo_data/agaricus.txt.test') watchlist = [(dtrain, 'train'), (dtest, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1} xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

不平衡對比

使用weight給樣本賦予權(quán)重。

label=1,權(quán)重設(shè)置為3

label=0,? 權(quán)重設(shè)置為1

print("\n--------- custom set weight=3, scale_pos_weight=1-----------") dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True) dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True) train_weight = [1 if i == 0 else 3 for i in dtrain.get_label().tolist()] test_weight = [1 if i == 0 else 3 for i in dtest.get_label().tolist()] dtrain2 = xgb.DMatrix('../demo_data/agaricus.txt.train', weight=train_weight, silent=True) dtest2 = xgb.DMatrix('../demo_data/agaricus.txt.test', weight=test_weight, silent=True) watchlist = [(dtrain2, 'train'), (dtest2, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1} xgb.train(params=params, dtrain=dtrain2, num_boost_round=5, evals=watchlist, verbose_eval=1)

?將正樣本復(fù)制成原來的3倍,和負(fù)樣本拼起來組成訓(xùn)練集訓(xùn)練

print("\n---------read agaricus.txt.xxx_weight3 scale_pos_weight = 1 -----------") dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train_weight3') dtest = xgb.DMatrix('../demo_data/agaricus.txt.test_weight3') watchlist = [(dtrain, 'train'), (dtest, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1} xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

scale_pos_weight = 3

print("\n--------- scale_pos_weight = 3-----------") dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True) dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True) watchlist = [(dtrain, 'train'), (dtest, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 3} xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

自定義損失函數(shù),

將正樣本的logloss設(shè)置為負(fù)樣本的3倍,然后求一階導(dǎo)和二階導(dǎo).

print("\n---------custom set weight=3, scale_pos_weight=1, use custom obj-----------")from sklearn.metrics import roc_auc_scoreratio = 3def logistic_obj(p, dtrain):y = dtrain.get_label()grad = p * (ratio * y + 1 - y) - ratio * yhess = p * (1 - p) * (beta * y + 1 - y)return grad, hessdef logistic_obj_feval(p, dtrain):y = dtrain.get_label()score = roc_auc_score(y, p)return 'feval-auc', scoredtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True) dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True) train_weight = [1 if i == 0 else 3 for i in dtrain.get_label().tolist()] test_weight = [1 if i == 0 else 3 for i in dtest.get_label().tolist()] dtrain2 = xgb.DMatrix('../demo_data/agaricus.txt.train', weight=train_weight, silent=True) dtest2 = xgb.DMatrix('../demo_data/agaricus.txt.test', weight=test_weight, silent=True) watchlist = [(dtrain2, 'train'), (dtest2, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1} xgb.train(params=params, dtrain=dtrain2, num_boost_round=5,evals=watchlist, verbose_eval=1, obj=logistic_obj, feval=logistic_obj_feval)

5. 設(shè)置 subsample

如果參數(shù)subsample < 1 ,此時將正樣本復(fù)制成原來的3倍,訓(xùn)練結(jié)果還是會不一樣,因為樣本總數(shù)改變了,子采樣就會不一樣, 其他情況輸出不會變。

print("\n--------- scale_pos_weight = 3, subsample=0.8-----------") dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True) dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True) watchlist = [(dtrain, 'train'), (dtest, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 3, "subsample":0.8} xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)print("\n---------read agaricus.txt.xxx_weight3 scale_pos_weight = 1, subsample=0.8 -----------") dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train_weight3') dtest = xgb.DMatrix('../demo_data/agaricus.txt.test_weight3') watchlist = [(dtrain, 'train'), (dtest, 'eval')] params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1, "subsample":0.8} xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

三 結(jié)論

sample_weight參數(shù)允許您為每個訓(xùn)練示例指定不同的權(quán)重。 scale_pos_weight參數(shù)允許您為整類示例(“正”類)提供權(quán)重。

這些對應(yīng)于成本敏感學(xué)習(xí)的兩種不同方法。如果您認(rèn)為錯誤分類正面示例(錯過癌癥患者)的成本對于所有正面示例都是相同的(但比錯誤分類負(fù)面示例的成本更高,例如告訴某人他們實際上沒有癌癥),那么您可以指定一個通過 scale_pos_weight 獲得所有正面示例的權(quán)重.

參考:

樣本不平衡問題操作手冊 - 知乎


不平衡處理:xgboost 中scale_pos_weight、給樣本設(shè)置權(quán)重weight、 自定義損失函數(shù) 和 簡單復(fù)制正樣本的區(qū)別_大風(fēng)車-CSDN博客

總結(jié)

以上是生活随笔為你收集整理的[机器学习] XGBoost 样本不平衡问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。