本篇文章僅僅是之前自己學習xgboost時的學習筆記,僅作備忘錄之用。本篇文章大部分內容摘自多篇文章的精華部分,文章中及最後已註明出處,在此一併感謝各位大佬!
在能看懂下述推導的情況下,首先推薦一個這篇文章 ,寫的炒雞棒!吐血推薦!!!
XGBoost 推導思路
圖片來源及詳細解釋見:文章 。建議參考陳天齊大佬的PDF 。
XGBoost 詳細推導過程
XGBoost的目標函數由訓練損失 和正則化項 兩部分組成,目標函數定義如下:
O b j = ∑ i = 1 n l ( y i , y ^ i ) + ∑ k = 1 K Ω ( f k )
O b j = \sum _ { i = 1 } ^ { n } l \left( y _ { i } , \hat { y } _ { i } \right) + \sum _ { k = 1 } ^ { K } \Omega \left( f _ { k } \right)
O b j = i = 1 ∑ n l ( y i , y ^ i ) + k = 1 ∑ K Ω ( f k )
由於XGBoost是一個加法模型,因此,預測得分是每棵樹打分的累加之和 。(注意預測的是得分 score ,不是概率值!)
y ^ i = ∑ k = 1 K f k ( x i ) , f k ∈ F ( s p a c e o f f u n c t i o n s c o n t a i n i n g a l l R e g r e s s i o n t r e e s )
\hat { y } _ { i } = \sum _ { k = 1 } ^ { K } f _ { k } \left( x _ { i } \right) , \quad f _ { k } \in \mathcal { F }(space\ of\ functions\ containing\ all\ Regression\ trees)
y ^ i = k = 1 ∑ K f k ( x i ) , f k ∈ F ( s p a c e o f f u n c t i o n s c o n t a i n i n g a l l R e g r e s s i o n t r e e s )
我們已知XGBoost 是一個加法模型 ,假設我們第t t t 次迭代要訓練的樹模型是 f t ( ) f_t() f t ( ) ,則有:(理解:新生成的樹是要擬合上次預測的殘差的)
y ^ i ( t ) = ∑ k = 1 t f k ( x i ) = y ^ i ( t − 1 ) + f t ( x i )
\hat { y } _ { i } ^ { ( t ) } = \sum _ { k = 1 } ^ { t } f _ { k } \left( x _ { i } \right) = \hat { y } _ { i } ^ { ( t - 1 ) } + f _ { t } \left( x _ { i } \right)
y ^ i ( t ) = k = 1 ∑ t f k ( x i ) = y ^ i ( t − 1 ) + f t ( x i )
注意上式中,只有一個變量,那就是第 t t t 棵樹:f t ( x i ) f _ { t } \left( x _ { i } \right) f t ( x i ) , 同時注意此時 y ^ i ( t − 1 ) \hat { y } _ { i } ^ { ( t - 1 ) } y ^ i ( t − 1 ) 和 ∑ k = 1 t − 1 Ω ( f k ) \sum _ { k = 1 } ^ { t - 1 } \Omega \left( f _ { k } \right) ∑ k = 1 t − 1 Ω ( f k ) 爲已知的常量。
所以此時的目標函數 就可以變爲:
Obj ( t ) = ∑ i = 1 n l ( y i , y ^ i ( t ) ) + ∑ i = 1 t Ω ( f i ) = ∑ i = 1 n l ( y i , y ^ i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) + c o n s t a n t
\begin{aligned} \operatorname { Obj } ^ { ( t ) } & = \sum _ { i = 1 } ^ { n } l \left( y _ { i } , \ \hat { y } _ { i } ^ { ( t ) } \right) + \sum _ { i = 1 } ^ { t } \Omega \left( f _ { i } \right) \\ & = \sum _ { i = 1 } ^ { n } l \left( y _ { i } , \ \hat { y } _ { i } ^ { ( t - 1 ) } + f _ { t } \left( x _ { i } \right) \right) + \Omega \left( f _ { t } \right) + constant \end{aligned}
O b j ( t ) = i = 1 ∑ n l ( y i , y ^ i ( t ) ) + i = 1 ∑ t Ω ( f i ) = i = 1 ∑ n l ( y i , y ^ i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) + c o n s t a n t
考慮二階泰勒展開 :f ( x + Δ x ) ≃ f ( x ) + f ′ ( x ) Δ x + 1 2 f ′ ′ ( x ) Δ x 2 f ( x + \Delta x ) \simeq f ( x ) + f ^ { \prime } ( x ) \Delta x + \frac { 1 } { 2 } f ^ { \prime \prime } ( x ) \Delta x ^ { 2 } f ( x + Δ x ) ≃ f ( x ) + f ′ ( x ) Δ x + 2 1 f ′ ′ ( x ) Δ x 2
那麼,我們的損失函數 就可以轉化爲下式:
O b j ( t ) ≃ ∑ i = 1 n [ l ( y i , y ^ i ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) + c o n s t a n t
O b j ^ { ( t ) } \simeq \sum _ { i = 1 } ^ { n } \left[ l \left( y _ { i } ,\ \hat { y } _ { i } ^ { ( t - 1 ) } \right) + g _ { i } f _ { t } \left( x _ { i } \right) + \frac { 1 } { 2 } h _ { i } f _ { t } ^ { 2 } \left( x _ { i } \right) \right] + \Omega \left( f _ { t } \right) + constant
O b j ( t ) ≃ i = 1 ∑ n [ l ( y i , y ^ i ( t − 1 ) ) + g i f t ( x i ) + 2 1 h i f t 2 ( x i ) ] + Ω ( f t ) + c o n s t a n t
去掉上式的全部常數項,得到目標函數 :
O b j ( t ) ≃ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t )
O b j ^ { ( t ) } \simeq \sum _ { i = 1 } ^ { n } \left[ g _ { i } f _ { t } \left( x _ { i } \right) + \frac { 1 } { 2 } h _ { i } f _ { t } ^ { 2 } \left( x _ { i } \right) \right] + \Omega \left( f _ { t } \right)
O b j ( t ) ≃ i = 1 ∑ n [ g i f t ( x i ) + 2 1 h i f t 2 ( x i ) ] + Ω ( f t )
其中:g i = ∂ y ^ i ( t − 1 ) ( y i − y ^ i ( t − 1 ) ) 2 = 2 ( y ^ i ( t − 1 ) − y i ) h i = ∂ y ^ i ( t − 1 ) 2 ( y i − y ^ i ( t − 1 ) ) 2 = 2 g _ { i } = \partial _ { \hat { y }_i ^ { ( t - 1 ) } } \left( y _ { i } - \hat { y }_i ^ { ( t - 1 ) } \right) ^ { 2 } = 2 \left( \hat { y }_i ^ { ( t - 1 ) } - y _ { i } \right) \quad h _ { i } = \partial _ { \hat { y }_i ^ { ( t - 1 ) } } ^ { 2 } \left( y _ { i } - \hat { y }_i ^ { ( t - 1 ) } \right) ^ { 2 } = 2 g i = ∂ y ^ i ( t − 1 ) ( y i − y ^ i ( t − 1 ) ) 2 = 2 ( y ^ i ( t − 1 ) − y i ) h i = ∂ y ^ i ( t − 1 ) 2 ( y i − y ^ i ( t − 1 ) ) 2 = 2
此外,我們還要定義樹的複雜度:
下面就是葉子節點分組 :
Define the instance set in leaf j j j as I j = { i ∣ q ( x i ) = j } I _ { j } = \left\{ \ i\ | \ q \left( x _ { i } \right) = j \right\} I j = { i ∣ q ( x i ) = j }
Regroup the objective by each leaf:
Obj ( t ) ≃ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) = ∑ i = 1 n [ g i w q ( x i ) + 1 2 h i w q ( x i ) 2 ] + γ T + λ 1 2 ∑ j = 1 T w j 2 = ∑ j = 1 T [ ( ∑ i ∈ I j g i ) w j + 1 2 ( ∑ i ∈ I j h i + λ ) w j 2 ] + γ T
\begin{aligned} \operatorname { Obj } ^ { ( t ) } & \simeq \sum _ { i = 1 } ^ { n } \left[ g _ { i } f _ { t } \left( x _ { i } \right) + \frac { 1 } { 2 } h _ { i } f _ { t } ^ { 2 } \left( x _ { i } \right) \right] + \Omega \left( f _ { t } \right) \\ & = \sum _ { i = 1 } ^ { n } \left[ g _ { i } w _ { q \left( x _ { i } \right) } + \frac { 1 } { 2 } h _ { i } w _ { q \left( x _ { i } \right) } ^ { 2 } \right] + \gamma T + \lambda \frac { 1 } { 2 } \sum _ { j = 1 } ^ { T } w _ { j } ^ { 2 } \\ & = \sum _ { j = 1 } ^ { T } \left[ \left( \sum _ { i \in I _ { j } } g _ { i } \right) w _ { j } + \frac { 1 } { 2 } \left( \sum _ { i \in I _ { j } } h _ { i } + \lambda \right) w _ { j } ^ { 2 } \right] + \gamma T \end{aligned}
O b j ( t ) ≃ i = 1 ∑ n [ g i f t ( x i ) + 2 1 h i f t 2 ( x i ) ] + Ω ( f t ) = i = 1 ∑ n [ g i w q ( x i ) + 2 1 h i w q ( x i ) 2 ] + γ T + λ 2 1 j = 1 ∑ T w j 2 = j = 1 ∑ T ⎣ ⎡ ⎝ ⎛ i ∈ I j ∑ g i ⎠ ⎞ w j + 2 1 ⎝ ⎛ i ∈ I j ∑ h i + λ ⎠ ⎞ w j 2 ⎦ ⎤ + γ T
爲進一步簡化該式,我們進行如下定義:
G j = ∑ i ∈ I j g i H j = ∑ i ∈ I j h i
G _ { j } = \sum _ { i \in I _ { j } } g _ { i } \quad H _ { j } = \sum _ { i \in I _ { j } } h _ { i }
G j = i ∈ I j ∑ g i H j = i ∈ I j ∑ h i
含義如下:
G j G_j G j :葉子結點 j j j 所包含樣本 的一階偏導數累加之和,是一個常量;
H j H_j H j :葉子結點 j j j 所包含樣本 的二階偏導數累加之和,是一個常量;
將 G j G_j G j 和 H j H_j H j 帶入目標式 Obj ( t ) \operatorname { Obj } ^ { ( t ) } O b j ( t ) ,得到我們最終的目標函數 (注意,此時式中的變量只剩下第 t t t 棵樹的權重向量 W W W ):
O b j ( t ) = ∑ j = 1 T [ ( ∑ i ∈ I j g i ) w j + 1 2 ( ∑ i ∈ I j h i + λ ) w j 2 ] + γ T = ∑ j = 1 T [ G j w j + 1 2 ( H j + λ ) w j 2 ] + γ T
\begin{aligned} O b j ^ { ( t ) } & = \sum _ { j = 1 } ^ { T } \left[ \left( \sum _ { i \in I _ { j } } g _ { i } \right) w _ { j } + \frac { 1 } { 2 } \left( \sum _ { i \in I _ { j } } h _ { i } + \lambda \right) w _ { j } ^ { 2 } \right] + \gamma T \\ & = \sum _ { j = 1 } ^ { T } \left[ G _ { j } w _ { j } + \frac { 1 } { 2 } \left( H _ { j } + \lambda \right) w _ { j } ^ { 2 } \right] + \gamma T \end{aligned}
O b j ( t ) = j = 1 ∑ T ⎣ ⎡ ⎝ ⎛ i ∈ I j ∑ g i ⎠ ⎞ w j + 2 1 ⎝ ⎛ i ∈ I j ∑ h i + λ ⎠ ⎞ w j 2 ⎦ ⎤ + γ T = j = 1 ∑ T [ G j w j + 2 1 ( H j + λ ) w j 2 ] + γ T
下面是樹結構打分 :
根據上面推導出的最終的目標函數 ,我們可以發現:這就是初中數學的一個簡單的一元二次函數求極值 的問題。對於每個葉子結點 j j j , 可以將其從目標式 Obj ( t ) \operatorname { Obj } ^ { ( t ) } O b j ( t ) 中拆解出來:
G j w j + 1 2 ( H j + λ ) w j 2
G _ { j } w _ { j } + \frac { 1 } { 2 } \left( H _ { j } + \lambda \right) w _ { j } ^ { 2 }
G j w j + 2 1 ( H j + λ ) w j 2
G j G _ { j } G j 和 H j H_j H j 相對於第 t t t 棵樹來說是可以計算出來的。那麼,這個式子就是一個只包含一個變量 葉子結點權重w j w_j w j 的一元二次函數,我們可以通過最值公式 求出它的最值點。
再次分析一下目標函數 Obj ( t ) \operatorname { Obj } ^ { ( t ) } O b j ( t ) ,可以發現,各個葉子結點的目標子式是相互獨立的 ,也就是說,當每個葉子結點的子式都達到最值點時,整個目標函數式 Obj ( t ) \operatorname { Obj } ^ { ( t ) } O b j ( t ) 才達到最值點。
那麼,假設目前樹的結構已經固定 ,套用一元二次函數的最值公式,我們可以輕易求出,每個葉子結點的權重 w j w _ { j } w j 及其此時達到最優的 Obj ( t ) \operatorname { Obj } ^ { ( t ) } O b j ( t ) 的目標值:
至此,XGBoost大體的推導過程已經介紹完了,總結如下:
樹的生長細節
分裂一個結點
在實際訓練過程中,當建立第 t t t 棵樹時,XGBoost採用貪心法 進行樹結點的分裂:
從樹深爲0時開始:
對樹中的每個葉子結點 嘗試進行分裂;
每次分裂後,原來的一個葉子結點 繼續分裂爲左右兩個子葉子結點 ,原葉子結點中的樣本集將根據該結點的判斷規則分散到左右兩個葉子結點中;
新分裂一個結點後,我們需要檢測這次分裂是否會給損失函數帶來增益 ,增益的定義如下:
G a i n = O b j L + R − ( O b j L + O b j R ) = [ − 1 2 ( G L + G R ) 2 H L + H R + λ + γ ] − [ − 1 2 ( G L 2 H L + λ + G R 2 H R + λ ) + 2 γ ] = 1 2 [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 H L + H R + λ ] − γ
\begin{aligned} Gai n & = O b j _ { L + R } - \left( O b j _ { L } + O b j _ { R } \right) \\ & = \left[ - \frac { 1 } { 2 } \frac { \left( G _ { L } + G _ { R } \right) ^ { 2 } } { H _ { L } + H _ { R } + \lambda } + \gamma \right] - \left[ - \frac { 1 } { 2 } \left( \frac { G _ { L } ^ { 2 } } { H _ { L } + \lambda } + \frac { G _ { R } ^ { 2 } } { H _ { R } + \lambda } \right) + 2 \gamma \right] \\ & = \frac { 1 } { 2 } \left[ \frac { G _ { L } ^ { 2 } } { H _ { L } + \lambda } + \frac { G _ { R } ^ { 2 } } { H _ { R } + \lambda } - \frac { \left( G _ { L } + G _ { R } \right) ^ { 2 } } { H _ { L } + H _ { R } + \lambda } \right] - \gamma \end{aligned}
G a i n = O b j L + R − ( O b j L + O b j R ) = [ − 2 1 H L + H R + λ ( G L + G R ) 2 + γ ] − [ − 2 1 ( H L + λ G L 2 + H R + λ G R 2 ) + 2 γ ] = 2 1 [ H L + λ G L 2 + H R + λ G R 2 − H L + H R + λ ( G L + G R ) 2 ] − γ
如果增益G a i n > 0 Gain>0 G a i n > 0 ,即分裂爲兩個葉子節點後,目標函數下降了,那麼我們會考慮此次分裂的結果。
但是,在一個結點分裂時,可能有很多個分裂點,每個分裂點都會產生一個增益,如何才能尋找到最優的分裂點呢?接下來會講到。
尋找最佳分裂點
在分裂一個結點時,我們會有很多個候選分割點,尋找最佳分割點的大致步驟如下:
遍歷每個結點的每個特徵 ;
對每個特徵 ,按特徵值大小將特徵值排序 ;
線性掃描 ,找出每個特徵的最佳分裂特徵值;
在所有特徵中找出最好的分裂點 (分裂後增益最大的特徵及特徵值)
上面是一種貪心 的方法,每次進行分裂嘗試都要遍歷一遍全部候選分割點,也叫做全局掃描法 。
但當數據量過大導致內存無法一次載入或者在分佈式情況下,貪心算法的效率就會變得很低,全局掃描法不再適用。
基於此,XGBoost提出了一系列加快尋找最佳分裂點的方案:
特徵預排序+緩存 :XGBoost在訓練之前,預先對每個特徵按照特徵值大小進行排序,然後保存爲block結構,後面的迭代中會重複地使用這個結構,使計算量大大減小。
分位點近似法 :對每個特徵按照特徵值排序後,採用類似分位點選取的方式,僅僅選出常數個特徵值作爲該特徵的候選分割點,在尋找該特徵的最佳分割點時,從候選分割點中選出最優的一個。
並行查找 :由於各個特性已預先存儲爲block結構,XGBoost支持利用多個線程並行地計算每個特徵的最佳分割點,這不僅大大提升了結點的分裂速度,也極利於大規模訓練集的適應性擴展。
停止生長
一棵樹不會一直生長下去,下面是一些常見的限制條件。
當新引入的一次分裂所帶來的增益 G a i n < 0 Gain<0 G a i n < 0 時,放棄當前的分裂。這是訓練損失 和模型結構複雜度 的博弈過程。
當樹達到最大深度時,停止建樹,因爲樹的深度太深容易出現過擬合,這裏需要設置一個超參數m a x d e p t h max_depth m a x d e p t h 。
當引入一次分裂後,重新計算新生成的左、右兩個葉子結點的樣本權重和。如果任一個葉子結點的樣本權重低於某一個閾值(官網api中這個權重指的是二階導數H j H_j H j ,即要求m i n ( H L , H j ) > m i n _ c h i l d _ w e i g h t min(H_L,\ H_j) > min\_child\_weight m i n ( H L , H j ) > m i n _ c h i l d _ w e i g h t ),也會放棄此次分裂。這涉及到一個超參數:最小樣本權重和 ,是指如果一個葉子節點包含的樣本數量太少也會放棄分裂,防止樹分的太細 ,這也是過擬合的一種措施。
每個葉子結點的樣本權值和計算方式如下:
w j ∗ = − G j H j + λ
w _ { j } ^ { * } = - \frac { G _ { j } } { H _ { j } + \lambda }
w j ∗ = − H j + λ G j
常見問題
XGB與GBDT、隨機森林等模型相比,有什麼優缺點?
XGB爲什麼可以並行訓練?
XGB用二階泰勒展開的優勢在哪?
XGB爲了防止過擬合,進行了哪些設計?
XGB如何處理缺失值?
XGB如何分裂一個結點?如何選擇特徵?
XGB中一顆樹停止生長的條件有哪些?
XGB葉子結點的權重有什麼含義?如何計算?
訓練一個XGB模型,經歷了哪些過程?調參步驟是什麼?
XGB如何給特徵評分?
面試題-參考答案: 珍藏版 | 20道XGBoost面試題
References
https://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf
https://www.jianshu.com/p/ac1c12f3fba1
https://zhuanlan.zhihu.com/p/92837676
https://www.zhihu.com/question/58883125
https://zhuanlan.zhihu.com/p/34679467
https://mp.weixin.qq.com/s?__biz=MzI1MzY0MzE4Mg==&mid=2247485159&idx=1&sn=d429aac8370ca5127e1e786995d4e8ec&chksm=e9d01626dea79f30043ab80652c4a859760c1ebc0d602e58e13490bf525ad7608a9610495b3d&scene=21#wechat_redirect
https://blog.csdn.net/v_JULY_v/article/details/81410574