XGBoost20題


1. 簡單介紹一下XGBoost 

首先需要說一說GBDT,它是一種基於boosting增強策略的加法模型,訓練的時候采用前向分布算法進行貪婪的學習,每次迭代都學習一棵CART樹來擬合之前 t-1 棵樹的預測結果與訓練樣本真實值的殘差。XGBoost對GBDT進行了一系列優化,比如損失函數進行了二階泰勒展開、目標函數加入正則項、支持並行和默認缺失值處理等,在可擴展性和訓練速度上有了巨大的提升,但其核心思想沒有大的變化。

2. XGBoost與GBDT有什么不同

  • 基分類器:XGBoost的基分類器不僅支持CART決策樹,還支持線性分類器,此時XGBoost相當於帶L1和L2正則化項的Logistic回歸(分類問題)或者線性回歸(回歸問題)。
  • 導數信息:XGBoost對損失函數做了二階泰勒展開,GBDT只用了一階導數信息,並且XGBoost還支持自定義損失函數,只要損失函數一階、二階可導。
  • 正則項:XGBoost的目標函數加了正則項, 相當於預剪枝,使得學習出來的模型更加不容易過擬合。
  • 列抽樣:XGBoost支持列采樣,與隨機森林類似,用於防止過擬合。
  • 缺失值處理:對樹中的每個非葉子結點,XGBoost可以自動學習出它的默認分裂方向。如果某個樣本該特征值缺失,會將其划入默認分支。
  • 並行化:注意不是tree維度的並行,而是特征維度的並行。XGBoost預先將每個特征按特征值排好序,存儲為塊結構,分裂結點時可以采用多線程並行查找每個特征的最佳分割點,極大提升訓練速度。

3. XGBoost為什么使用泰勒二階展開

  • 精准性:相對於GBDT的一階泰勒展開,XGBoost采用二階泰勒展開,可以更為精准的逼近真實的損失函數

  • 可擴展性:損失函數支持自定義,只需要新的損失函數二階可導。

4. XGBoost為什么可以並行訓練

  • XGBoost的並行,並不是說每棵樹可以並行訓練,XGB本質上仍然采用boosting思想,每棵樹訓練前需要等前面的樹訓練完成才能開始訓練。

  • XGBoost的並行,指的是特征維度的並行:在訓練之前,每個特征按特征值對樣本進行預排序,並存儲為Block結構,在后面查找特征分割點時可以重復使用,而且特征已經被存儲為一個個block結構,那么在尋找每個特征的最佳分割點時,可以利用多線程對每個block並行計算。

5. XGBoost為什么快

  • 分塊並行:訓練前每個特征按特征值進行排序並存儲為Block結構,后面查找特征分割點時重復使用,並且支持並行查找每個特征的分割點

  • 候選分位點:每個特征采用常數個分位點作為候選分割點

  • CPU cache 命中優化: 使用緩存預取的方法,對每個線程分配一個連續的buffer,讀取每個block中樣本的梯度信息並存入連續的Buffer中。

  • Block 處理優化:Block預先放入內存;Block按列進行解壓縮;將Block划分到不同硬盤來提高吞吐

6. XGBoost防止過擬合的方法

XGBoost在設計時,為了防止過擬合做了很多優化,具體如下:

  • 目標函數添加正則項:葉子節點個數+葉子節點權重的L2正則化
  • 列抽樣:訓練的時候只用一部分特征(不考慮剩余的block塊即可)
  • 子采樣:每輪計算可以不使用全部樣本,使算法更加保守
  • shrinkage: 可以叫學習率或步長,為了給后面的訓練留出更多的學習空間

7. XGBoost如何處理缺失值

XGBoost模型的一個優點就是允許特征存在缺失值。對缺失值的處理方式如下:

  • 在特征k上尋找最佳 split point 時,不會對該列特征 missing 的樣本進行遍歷,而只對該列特征值為 non-missing 的樣本上對應的特征值進行遍歷,通過這個技巧來減少了為稀疏離散特征尋找 split point 的時間開銷。

     

  • 在邏輯實現上,為了保證完備性,會將該特征值missing的樣本分別分配到左葉子結點和右葉子結點,兩種情形都計算一遍后,選擇分裂后增益最大的那個方向(左分支或是右分支),作為預測時特征值缺失樣本的默認分支方向。

     

  • 如果在訓練中沒有缺失值而在預測中出現缺失,那么會自動將缺失值的划分方向放到右子結點。

     

     

     

find_split時,缺失值處理的偽代碼

8. XGBoost中葉子結點的權重如何計算出來

XGBoost目標函數最終推導形式如下:

 

利用一元二次函數求最值的知識,當目標函數達到最小值Obj*時,每個葉子結點的權重為wj*。

具體公式如下:

 

9. XGBoost中的一棵樹的停止生長條件

  • 當新引入的一次分裂所帶來的增益Gain<0時,放棄當前的分裂。這是訓練損失和模型結構復雜度的博弈過程。

  • 當樹達到最大深度時,停止建樹,因為樹的深度太深容易出現過擬合,這里需要設置一個超參數max_depth。

  • 當引入一次分裂后,重新計算新生成的左、右兩個葉子結點的樣本權重和。如果任一個葉子結點的樣本權重低於某一個閾值,也會放棄此次分裂。這涉及到一個超參數:最小樣本權重和,是指如果一個葉子節點包含的樣本數量太少也會放棄分裂,防止樹分的太細。

10. RF和GBDT的區別

相同點:

  • 都是由多棵樹組成,最終的結果都是由多棵樹一起決定。

不同點:

  • 集成學習:RF屬於bagging思想,而GBDT是boosting思想
  • 偏差-方差權衡:RF不斷的降低模型的方差,而GBDT不斷的降低模型的偏差
  • 訓練樣本:RF每次迭代的樣本是從全部訓練集中有放回抽樣形成的,而GBDT每次使用全部樣本
  • 並行性:RF的樹可以並行生成,而GBDT只能順序生成(需要等上一棵樹完全生成)
  • 最終結果:RF最終是多棵樹進行多數表決(回歸問題是取平均),而GBDT是加權融合
  • 數據敏感性:RF對異常值不敏感,而GBDT對異常值比較敏感
  • 泛化能力:RF不易過擬合,而GBDT容易過擬合

 

11. XGBoost如何處理不平衡數據

對於不平衡的數據集,例如用戶的購買行為,肯定是極其不平衡的,這對XGBoost的訓練有很大的影響,XGBoost有兩種自帶的方法來解決:

第一種,如果你在意AUC,采用AUC來評估模型的性能,那你可以通過設置scale_pos_weight來平衡正樣本和負樣本的權重。例如,當正負樣本比例為1:10時,scale_pos_weight可以取10;

第二種,如果你在意概率(預測得分的合理性),你不能重新平衡數據集(會破壞數據的真實分布),應該設置max_delta_step為一個有限數字來幫助收斂(基模型為LR時有效)。

原話是這么說的:

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 prediction
      Balance the positive and negative weights, via scale_pos_weight
      Use AUC for evaluation
  If you care about predicting the right probability
      In such a case, you cannot re-balance the dataset
      In such a case, set parameter max_delta_step to a finite number (say 1) will help convergence

那么,源碼到底是怎么利用scale_pos_weight來平衡樣本的呢,是調節權重還是過采樣呢?請看源碼:

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

可以看出,應該是增大了少數樣本的權重。

除此之外,還可以通過上采樣、下采樣、SMOTE算法或者自定義代價函數的方式解決正負樣本不平衡的問題。

12. 比較LR和GBDT,說說什么情景下GBDT不如LR

先說說LR和GBDT的區別:

  • LR是線性模型,可解釋性強,很容易並行化,但學習能力有限,需要大量的人工特征工程
  • GBDT是非線性模型,具有天然的特征組合優勢,特征表達能力強,但是樹與樹之間無法並行訓練,而且樹模型很容易過擬合;

當在高維稀疏特征的場景下,LR的效果一般會比GBDT好。原因如下:

先看一個例子:

假設一個二分類問題,label為0和1,特征有100維,如果有1w個樣本,但其中只要10個正樣本1,而這些樣本的特征 f1的值為全為1,而其余9990條樣本的f1特征都為0(在高維稀疏的情況下這種情況很常見)。

我們都知道在這種情況下,樹模型很容易優化出一個使用f1特征作為重要分裂節點的樹,因為這個結點直接能夠將訓練數據划分的很好,但是當測試的時候,卻會發現效果很差,因為這個特征f1只是剛好偶然間跟y擬合到了這個規律,這也是我們常說的過擬合。

那么這種情況下,如果采用LR的話,應該也會出現類似過擬合的情況呀:y = W1*f1 + Wi*fi+….,其中 W1特別大以擬合這10個樣本。為什么此時樹模型就過擬合的更嚴重呢?

仔細想想發現,因為現在的模型普遍都會帶着正則項,而 LR 等線性模型的正則項是對權重的懲罰,也就是 W1一旦過大,懲罰就會很大,進一步壓縮 W1的值,使他不至於過大。但是,樹模型則不一樣,樹模型的懲罰項通常為葉子節點數和深度等,而我們都知道,對於上面這種 case,樹只需要一個節點就可以完美分割9990和10個樣本,一個結點,最終產生的懲罰項極其之小。

這也就是為什么在高維稀疏特征的時候,線性模型會比非線性模型好的原因了:帶正則化的線性模型比較不容易對稀疏特征過擬合。

13. XGBoost中如何對樹進行剪枝

  • 在目標函數中增加了正則項:使用葉子結點的數目和葉子結點權重的L2模的平方,控制樹的復雜度。

  • 在結點分裂時,定義了一個閾值,如果分裂后目標函數的增益小於該閾值,則不分裂。

  • 當引入一次分裂后,重新計算新生成的左、右兩個葉子結點的樣本權重和。如果任一個葉子結點的樣本權重低於某一個閾值(最小樣本權重和),也會放棄此次分裂。

  • XGBoost 先從頂到底建立樹直到最大深度,再從底到頂反向檢查是否有不滿足分裂條件的結點,進行剪枝。

14. XGBoost如何選擇最佳分裂點? 

XGBoost在訓練前預先將特征按照特征值進行了排序,並存儲為block結構,以后在結點分裂時可以重復使用該結構。
因此,可以采用特征並行的方法利用多個線程分別計算每個特征的最佳分割點,根據每次分裂后產生的增益,最終選擇增益最大的那個特征的特征值作為最佳分裂點。如果在計算每個特征的最佳分割點時,對每個樣本都進行遍歷,計算復雜度會很大,這種全局掃描的方法並不適用大數據的場景。XGBoost還提供了一種直方圖近似算法,對特征排序后僅選擇常數個候選分裂位置作為候選分裂點,極大提升了結點分裂時的計算效率。

15. XGBoost的Scalable性如何體現

  • 基分類器的scalability:弱分類器可以支持CART決策樹,也可以支持LR和Linear。
  • 目標函數的scalability:支持自定義loss function,只需要其一階、二階可導。有這個特性是因為泰勒二階展開,得到通用的目標函數形式。
  • 學習方法的scalability:Block結構支持並行化,支持 Out-of-core計算。

16. XGBoost如何評價特征的重要性

我們采用三種方法來評判XGBoost模型中特征的重要程度:

 

官方文檔:

(1)weight - the number of times a feature is used to split the data across all trees. 

(2)gain - the average gain of the feature when it is used in trees. 

(3)cover - the average coverage of the feature when it is used in trees.

  • weight :該特征在所有樹中被用作分割樣本的特征的總次數。

  • gain :該特征在其出現過的所有樹中產生的平均增益。

  • cover :該特征在其出現過的所有樹中的平均覆蓋范圍。

注意:覆蓋范圍這里指的是一個特征用作分割點后,其影響的樣本數量,即有多少樣本經過該特征分割到兩個子節點。

17. XGBooost參數調優的一般步驟

首先需要初始化一些基本變量,例如:

  • max_depth = 5

  • min_child_weight = 1

  • gamma = 0

  • subsample, colsample_bytree = 0.8

  • scale_pos_weight = 1

(1) 確定learning rate和estimator的數量learning rate可以先用0.1,用cv來尋找最優的estimators(2) max_depth和 min_child_weight

我們調整這兩個參數是因為,這兩個參數對輸出結果的影響很大。我們首先將這兩個參數設置為較大的數,然后通過迭代的方式不斷修正,縮小范圍。

max_depth,每棵子樹的最大深度,check from range(3,10,2)。

min_child_weight,子節點的權重閾值,check from range(1,6,2)。

如果一個結點分裂后,它的所有子節點的權重之和都大於該閾值,該葉子節點才可以划分。

(3) gamma也稱作最小划分損失min_split_loss,check from 0.1 to 0.5,指的是,對於一個葉子節點,當對它采取划分之后,損失函數的降低值的閾值。

  • 如果大於該閾值,則該葉子節點值得繼續划分

  • 如果小於該閾值,則該葉子節點不值得繼續划分

(4) subsample, colsample_bytree

subsample是對訓練的采樣比例

colsample_bytree是對特征的采樣比例

both check from 0.6 to 0.9

(5) 正則化參數

alpha 是L1正則化系數,try 1e-5, 1e-2, 0.1, 1, 100

lambda 是L2正則化系數

(6) 降低學習率降低學習率的同時增加樹的數量,通常最后設置學習率為0.01~0.1

18. XGBoost模型如果過擬合了怎么解決

當出現過擬合時,有兩類參數可以緩解:
第一類參數:用於直接控制模型的復雜度。包括max_depth,min_child_weight,gamma 等參數第二類參數:用於增加隨機性,從而使得模型在訓練時對於噪音不敏感。包括subsample,colsample_bytree還有就是直接減小learning rate,但需要同時增加estimator 參數。

19.為什么XGBoost相比某些模型對缺失值不敏感

對存在缺失值的特征,一般的解決方法是:

  • 離散型變量:用出現次數最多的特征值填充;

  • 連續型變量:用中位數或均值填充;

一些模型如SVM和KNN,其模型原理中涉及到了對樣本距離的度量,如果缺失值處理不當,最終會導致模型預測效果很差。而樹模型對缺失值的敏感度低,大部分時候可以在數據缺失時時使用。原因就是,一棵樹中每個結點在分裂時,尋找的是某個特征的最佳分裂點(特征值),完全可以不考慮存在特征值缺失的樣本,也就是說,如果某些樣本缺失的特征值缺失,對尋找最佳分割點的影響不是很大。XGBoost對缺失數據有特定的處理方法,參考第7題。因此,對於有缺失值的數據在經過缺失處理后:

  • 當數據量很小時,優先用朴素貝葉斯
  • 數據量適中或者較大,用樹模型,優先XGBoost
  • 數據量較大,也可以用神經網絡
  • 避免使用距離度量相關的模型,如KNN和SVM

20. XGBoost和LightGBM的區別

 

(1)樹生長策略:XGB采用level-wise的分裂策略,LGB采用leaf-wise的分裂策略。XGB對每一層所有節點做無差別分裂,但是可能有些節點增益非常小,對結果影響不大,帶來不必要的開銷。Leaf-wise是在所有葉子節點中選取分裂收益最大的節點進行的,但是很容易出現過擬合問題,所以需要對最大深度做限制 。
(2)分割點查找算法:XGB使用特征預排序算法,LGB使用基於直方圖的切分點算法,其優勢如下:

  • 減少內存占用,比如離散為256個bin時,只需要用8位整形就可以保存一個樣本被映射為哪個bin(這個bin可以說就是轉換后的特征),對比預排序的exact greedy算法來說(用int_32來存儲索引+ 用float_32保存特征值),可以節省7/8的空間。
  • 計算效率提高,預排序的Exact greedy對每個特征都需要遍歷一遍數據,並計算增益,復雜度為𝑂(#𝑓𝑒𝑎𝑡𝑢𝑟𝑒×#𝑑𝑎𝑡𝑎)。而直方圖算法在建立完直方圖后,只需要對每個特征遍歷直方圖即可,復雜度為𝑂(#𝑓𝑒𝑎𝑡𝑢𝑟𝑒×#𝑏𝑖𝑛𝑠)。
  • LGB還可以使用直方圖做差加速,一個節點的直方圖可以通過父節點的直方圖減去兄弟節點的直方圖得到,從而加速計算
但實際上xgboost的近似直方圖算法也類似於lightgbm這里的直方圖算法,為什么xgboost的近似算法比lightgbm還是慢很多呢?xgboost在每一層都動態構建直方圖, 因為xgboost的直方圖算法不是針對某個特定的feature,而是所有feature共享一個直方圖(每個樣本的權重是二階導),所以每一層都要重新構建直方圖,而lightgbm中對每個特征都有一個直方圖,所以構建一次直方圖就夠了。

(3)支持離散變量:無法直接輸入類別型變量,因此需要事先對類別型變量進行編碼(例如獨熱編碼),而LightGBM可以直接處理類別型變量。(4)緩存命中率:XGB使用Block結構的一個缺點是取梯度的時候,是通過索引來獲取的,而這些梯度的獲取順序是按照特征的大小順序的,這將導致非連續的內存訪問,可能使得CPU cache緩存命中率低,從而影響算法效率。而LGB是基於直方圖分裂特征的,梯度信息都存儲在一個個bin中,所以訪問梯度是連續的,緩存命中率高。(5)LightGBM 與 XGboost 的並行策略不同:

    • 特征並行 :LGB特征並行的前提是每個worker留有一份完整的數據集,但是每個worker僅在特征子集上進行最佳切分點的尋找;worker之間需要相互通信,通過比對損失來確定最佳切分點;然后將這個最佳切分點的位置進行全局廣播,每個worker進行切分即可。XGB的特征並行與LGB的最大不同在於XGB每個worker節點中僅有部分的列數據,也就是垂直切分,每個worker尋找局部最佳切分點,worker之間相互通信,然后在具有最佳切分點的worker上進行節點分裂,再由這個節點廣播一下被切分到左右節點的樣本索引號,其他worker才能開始分裂。二者的區別就導致了LGB中worker間通信成本明顯降低,只需通信一個特征分裂點即可,而XGB中要廣播樣本索引。

    • 數據並行 :當數據量很大,特征相對較少時,可采用數據並行策略。LGB中先對數據水平切分,每個worker上的數據先建立起局部的直方圖,然后合並成全局的直方圖,采用直方圖相減的方式,先計算樣本量少的節點的樣本索引,然后直接相減得到另一子節點的樣本索引,這個直方圖算法使得worker間的通信成本降低一倍,因為只用通信以此樣本量少的節點。XGB中的數據並行也是水平切分,然后單個worker建立局部直方圖,再合並為全局,不同在於根據全局直方圖進行各個worker上的節點分裂時會單獨計算子節點的樣本索引,因此效率賊慢,每個worker間的通信量也就變得很大。

    • 投票並行(LGB):當數據量和維度都很大時,選用投票並行,該方法是數據並行的一個改進。數據並行中的合並直方圖的代價相對較大,尤其是當特征維度很大時。大致思想是:每個worker首先會找到本地的一些優秀的特征,然后進行全局投票,根據投票結果,選擇top的特征進行直方圖的合並,再尋求全局的最優分割點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM