上篇我們對傳統的GBDT算法原理進行了探討,本篇我們來探討一個具有王者地位的算法:XGBOOST(Extreme Gradient Boosting
)。XGBOOST是來自於華盛頓大學的一個研究項目,2016年由陳天奇和Carlos Guestrin在KDD上發表:XGBoost: A Scalable Tree Boosting System 。自此之後,XGBOOST不僅在kaggle比賽中贏得一席之地,而且也推動了工業領域的一些前沿應用的發展。XGBOOST是我們處理中小型結構化數據必須要掌握的一個殺手鐗。
本篇我們主要參考陳天奇博士介紹XGBOOST的PPT:Boosted Trees 。
1)CART迴歸樹
CART迴歸樹既可以處理分類任務又可以處理迴歸任務。CART算法對訓練樣本集的每個特徵遞歸的進行二分判斷,將特徵空間劃分爲有限的單元,每個單元具有一定的權重。簡單的可以認爲,CART迴歸樹是一個葉子節點具有權重的二叉決策樹。CART迴歸樹有兩個特點:
決策規則和決策樹是一樣的;
決策樹的每個葉子節點都包含一個權重;
下圖就是一個迴歸決策樹的示例:
假如某決策樹的葉子節點數目爲T T T ,每個葉子節點的權重爲w → = { w 1 , w 2 , . . . w T } \overrightarrow{w}=\left\{w_1,w_2,...w_T\right\} w = { w 1 , w 2 , . . . w T } ,樣本x x x 落在葉節點q q q 中,決策樹模型f ( x ) f(x) f ( x ) 可以定義爲:
f t ( x ) = w q ( x ) w ∈ w → , q : R d → { 1 , 2 , . . . T } f_t(x) = w_{q(x)} \quad w \in \overrightarrow{w},q:R^d\rightarrow \left\{1,2,...T\right\} f t ( x ) = w q ( x ) w ∈ w , q : R d → { 1 , 2 , . . . T }
從上式中可以看出,決策樹的兩個核心爲:樹的結構q q q ,葉節點的權重w w w 。確定樹的結構和葉節點的權重便可以確定一顆決策樹。
在決策樹算法原理 中我們瞭解到,決策樹比較容易過擬合,因此會對決策樹進行剪枝操作。那麼我們該如何衡量決策樹的複雜度呢?我們可以使用,樹的深度,葉節點數量,葉子節點權重的L 2 L2 L 2 正則等。這裏我們使用葉節點的數量和葉子節點權重的L 2 L2 L 2 正則表示決策樹模型的複雜度,數學表達式爲:
Ω ( f t ) = γ T + 1 2 λ ∑ j = 1 T w j 2 \Omega(f_t) =\gamma T+\frac{1}{2} \lambda \sum_{j=1}^Tw_j^2 Ω ( f t ) = γ T + 2 1 λ j = 1 ∑ T w j 2
其中,T T T 爲葉節點的個數,w w w 爲葉節點所對應的權重,γ \gamma γ 爲收縮係數,λ \lambda λ 爲L 2 L2 L 2 平滑係數。下圖即爲一個決策樹模型複雜度的示例:
2)XGBOOST目標函數
XGBOOST基於Boosting框架,它採用的是前向優化算法,即從前往後,逐漸建立基模型來優化逼近目標函數,具體過程如下:
y ^ i ( 0 ) = 0 \hat y_i^{(0)}=0 y ^ i ( 0 ) = 0
y ^ i ( 1 ) = f 1 ( x i ) = y ^ i ( 0 ) + f 1 ( x i ) \hat y_i^{(1)}=f_1(x_i)=\hat y_i^{(0)} +f_1(x_i) y ^ i ( 1 ) = f 1 ( x i ) = y ^ i ( 0 ) + f 1 ( x i )
y ^ i ( 2 ) = f 1 ( x i ) + f 2 ( x i ) = y ^ i ( 1 ) + f 2 ( x i ) \hat y_i^{(2)}=f_1(x_i) + f_2(x_i)=\hat y_i^{(1)} +f_2(x_i) y ^ i ( 2 ) = f 1 ( x i ) + f 2 ( x i ) = y ^ i ( 1 ) + f 2 ( x i )
. . . ... . . .
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}^tf_k(x_i)=\hat y_i^{(t-1)} +f_t(x_i) y ^ i ( t ) = ∑ k = 1 t f k ( x i ) = y ^ i ( t − 1 ) + f t ( x i )
從上式中,我們可以看出,每一步我們都是要訓練一個新的基模型f t ( x i ) f_t(x_i) f t ( x i ) ,那麼我們的目標就是讓訓練的新模型使得誤差最小,即目標函數爲:
O b j ( t ) = ∑ i = 1 n l ( y i , y ^ i ) + ∑ i = 1 t Ω ( f i ) Obj^{(t)}=\sum_{i=1}^nl(y_i,\hat y_i) +\sum_{i=1}^t\Omega(f_i) O b j ( t ) = i = 1 ∑ n l ( y i , y ^ i ) + 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 =\sum_{i=1}^nl(y_i,\hat y_i^{(t-1)} +f_t(x_i))+\Omega(f_t)+constant = 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 t ) \Omega(f_t) Ω ( f t ) 爲模型複雜度,用來防止模型過擬合,平衡模型偏差和方差的。
由泰勒二階展開式可知:
f ( x + Δ x ) ≈ f ( x ) + f ′ ( x ) Δ x + 1 2 f ′ ′ ( x ) Δ x 2 f(x+\Delta x)\approx f(x)+f'(x)\Delta x+\frac{1}{2}f''(x)\Delta x^2 f ( x + Δ x ) ≈ f ( x ) + f ′ ( x ) Δ x + 2 1 f ′ ′ ( x ) Δ x 2
我們可以將y ^ i \hat y_i y ^ i 看出f ( x + Δ x ) f(x+\Delta x) f ( x + Δ x ) ,y ^ i ( t − 1 ) \hat y_i^{(t-1)} y ^ i ( t − 1 ) 即爲f ( x ) f(x) f ( x ) ,f t ( x i ) f_t(x_i) f t ( x i ) 即爲Δ x \Delta x Δ x ,利用泰勒二階展開式,對目標函數進行近似展開得:
O b j ( t ) ≈ ∑ i = 1 n [ l ( y i , y ^ i ( t − 1 ) ) + ∂ y ^ t − 1 l ( y i , y ^ i ( t − 1 ) ) f t ( x i ) + 1 2 ∂ y ^ t − 1 2 l ( y i , y ^ i ( t − 1 ) ) f t ( x i ) 2 ] + Ω ( f t ) + c o n s t a n t Obj^{(t)}\approx \sum_{i=1}^n[l(y_i,\hat y_i^{(t-1)})+\partial_{\hat y^{t-1}}l(y_i,\hat y_i^{(t-1)})f_t(x_i)
+\frac{1}{2}\partial_{\hat y^{t-1}}^2l(y_i,\hat y_i^{(t-1)})f_t(x_i)^2]+\Omega(f_t)+constant O b j ( t ) ≈ i = 1 ∑ n [ l ( y i , y ^ i ( t − 1 ) ) + ∂ y ^ t − 1 l ( y i , y ^ i ( t − 1 ) ) f t ( x i ) + 2 1 ∂ y ^ t − 1 2 l ( y i , y ^ i ( t − 1 ) ) f t ( x i ) 2 ] + Ω ( f t ) + c o n s t a n t
爲了簡化目標函數,令g i = ∂ y ^ t − 1 l ( y i , y ^ i ( t − 1 ) ) , h i = ∂ y ^ t − 1 2 l ( y i , y ^ i ( t − 1 ) ) g_i=\partial_{\hat y^{t-1}}l(y_i,\hat y_i^{(t-1)}),h_i=\partial_{\hat y^{t-1}}^2l(y_i,\hat y_i^{(t-1)}) g i = ∂ y ^ t − 1 l ( y i , y ^ i ( t − 1 ) ) , h i = ∂ y ^ t − 1 2 l ( y i , y ^ i ( t − 1 ) ) ,目標函數爲:
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 ( x i ) 2 ] + Ω ( f t ) + c o n s t a n t Obj^{(t)}\approx \sum_{i=1}^n[l(y_i,\hat y_i^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2]+\Omega(f_t)+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 ( x i ) 2 ] + Ω ( f t ) + c o n s t a n t
= ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t ( x i ) 2 ] + Ω ( f t ) + ∑ i = 1 n l ( y i , y ^ i ( t − 1 ) ) + c o n s t a n t =\sum_{i=1}^n[g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2]+\Omega(f_t)+ \sum_{i=1}^nl(y_i,\hat y_i^{(t-1)})+constant = i = 1 ∑ n [ g i f t ( x i ) + 2 1 h i f t ( x i ) 2 ] + Ω ( f t ) + i = 1 ∑ n l ( y i , y ^ i ( t − 1 ) ) + c o n s t a n t
由於對於第t t t 步而言,y ^ i ( t − 1 ) \hat y_i^{(t-1)} y ^ i ( t − 1 ) 是一個已知數,所以∑ i = 1 n l ( y i , y ^ i ( t − 1 ) ) \sum_{i=1}^nl(y_i,\hat y_i^{(t-1)}) ∑ i = 1 n l ( y i , y ^ i ( t − 1 ) ) 是一個常數,常數對於目標函數優化並無影響。因此,目標函數可以進一步簡化:
O b j ( t ) ≈ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t ( x i ) 2 ] + Ω ( f t ) Obj^{(t)}\approx\sum_{i=1}^n[g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2]+\Omega(f_t) O b j ( t ) ≈ i = 1 ∑ n [ g i f t ( x i ) + 2 1 h i f t ( x i ) 2 ] + Ω ( f t )
由上一節討論CART決策樹模型爲:
f t ( x ) = w q ( x ) w ∈ w → , q : R d → { 1 , 2 , . . . T } f_t(x) = w_{q(x)} \quad w \in \overrightarrow{w},q:R^d\rightarrow \left\{1,2,...T\right\} f t ( x ) = w q ( x ) w ∈ w , q : R d → { 1 , 2 , . . . T }
決策樹模型的複雜度可以表示爲:
Ω ( f t ) = γ T + 1 2 λ ∑ j = 1 T w j 2 \Omega(f_t) =\gamma T+\frac{1}{2} \lambda \sum_{j=1}^Tw_j^2 Ω ( f t ) = γ T + 2 1 λ j = 1 ∑ T w j 2
現定義I j I_j I j 表示第j j j 個葉子節點的樣本集合,即:
I j = { i ∣ q ( x i ) = j } I_j = \left\{i|q(x_i) = j\right\} I j = { i ∣ q ( x i ) = j }
現在我們使用每個葉子組合來重新表示目標函數:
O b j ( t ) ≈ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t ( x i ) 2 ] + Ω ( f t ) Obj^{(t)}\approx\sum_{i=1}^n[g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2]+\Omega(f_t) O b j ( t ) ≈ i = 1 ∑ n [ g i f t ( x i ) + 2 1 h i f t ( x i ) 2 ] + Ω ( 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 = \sum_{i=1}^n[g_i w_{q(x_i)}+\frac{1}{2}h_iw_{q(x_i)}^2]+\gamma T+\frac{1}{2} \lambda \sum_{j=1}^Tw_j^2 = 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 + 1 2 ( ∑ i ∈ I j h i + λ ) w j 2 ] + γ T =\sum_{j=1}^T[(\sum_{i \in I_j} g_i) w_j +\frac{1}{2}(\sum_{i \in I_j} h_i+\lambda)w_j^2]+\gamma T = j = 1 ∑ T [ ( i ∈ I j ∑ g i ) w j + 2 1 ( i ∈ I j ∑ h i + λ ) w j 2 ] + γ T
我們之前寫的目標函數是樣本的集合,現在都改寫成葉子結點的集合,由於一個葉子結點有多個樣本存在,因此纔有了∑ i ∈ I j g i \sum_{i \in I_j} g_i ∑ i ∈ I j g i 和 ∑ i ∈ I j h i \sum_{i \in I_j} h_i ∑ i ∈ I j h i 這兩項。
3)XGBOOST目標函數優化
由上節可知目標函數爲:
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 Obj^{(t)}=\sum_{j=1}^T[(\sum_{i \in I_j} g_i) w_j +\frac{1}{2}(\sum_{i \in I_j} h_i+\lambda)w_j^2]+\gamma T 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
我們定義G j = ∑ i ∈ I j g i , H j = ∑ i ∈ I j h i G_j=\sum_{i \in I_j} g_i,H_j=\sum_{i \in I_j} h_i G j = ∑ i ∈ I j g i , H j = ∑ i ∈ I j h i ,則目標函數可以寫成:
O b j ( t ) = ∑ j = 1 T [ G j w j + 1 2 ( H j + λ ) w j 2 ] + γ T Obj^{(t)}=\sum_{j=1}^T[G_j w_j +\frac{1}{2}(H_j+\lambda)w_j^2]+\gamma T O b j ( t ) = j = 1 ∑ T [ G j w j + 2 1 ( H j + λ ) w j 2 ] + γ T
我們回過頭來想想,如果一顆決策樹的結構已經確定,那麼每個葉子節點有哪些樣本也確定了,即G j , H j G_j,H_j G j , H j 已知,但每個葉子節點的權重是不確定,即w j w_j w j 不確定(我們要求的是w j w_j w j )。我們要求取目標函數最小值,那麼令目標函數一階導數爲0,得:
w ∗ = − G j H j + λ w^*=-\frac{G_j}{H_j+\lambda} w ∗ = − H j + λ G j
將w ∗ w^* w ∗ 帶入目標函數得:
O b j ( t ) = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T Obj^{(t)}=-\frac{1}{2}\sum_{j=1}^T\frac{G_j^2}{H_j+\lambda}+\gamma T O b j ( t ) = − 2 1 j = 1 ∑ T H j + λ G j 2 + γ T
上式越小,樹的結構就越好。下圖便能直觀的展示目標函數的計算過程。
4)子樹f t f_t f t 的生成
對於XGBOOST單顆子樹的生成,你可能會想到使用枚舉法:
枚舉所有可能存在的樹的結構q q q ;
計算所有樹的目標函數的得分;
O b j ( t ) = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T Obj^{(t)}=-\frac{1}{2}\sum_{j=1}^T\frac{G_j^2}{H_j+\lambda}+\gamma T O b j ( t ) = − 2 1 j = 1 ∑ T H j + λ G j 2 + γ T
確定目標函數最小的樹,求個葉子節點的最優權重;
w ∗ = − G j H J + λ w^*=-\frac{G_j}{H_J+\lambda} w ∗ = − H J + λ G j
但樹的結構有無限可能,無法枚舉,需要換一種方式。另一種方式是,使用貪婪算法。
從樹的深度爲0開始,每一節點都遍歷所有的特徵;
對於某一個特徵,先對特徵的值進行升序排序,分別計算特徵的各取值對應的o b j = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T obj=-\frac{1}{2}\sum_{j=1}^T\frac{G_j^2}{H_j+\lambda}+\gamma T o b j = − 2 1 ∑ j = 1 T H j + λ G j 2 + γ T 。在所有的特徵取值中,選擇o b j obj o b j 降低最小的特徵值作爲分裂點,最後在所有的特徵裏,選擇分割後Gain最高的特徵作爲當前節點分割特徵。Gain計算過程如下:O b j ( n o s p l i t ) = − 1 2 ∑ j = 1 t ( G L + G R ) 2 H L + H R + λ + γ T Obj_{(nosplit)}=-\frac{1}{2}\sum_{j=1}^t\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}+\gamma T O b j ( n o s p l i t ) = − 2 1 j = 1 ∑ t H L + H R + λ ( G L + G R ) 2 + γ T
O b j ( s p l i t ) = − 1 2 ∑ j = 1 t G L 2 H L + λ − 1 2 ∑ j = 1 t G R 2 H R + λ + γ ( T + 1 ) Obj_{(split)}=-\frac{1}{2}\sum_{j=1}^t\frac{G_L^2}{H_L+\lambda}-\frac{1}{2}\sum_{j=1}^t\frac{G_R^2}{H_R+\lambda}+\gamma(T+1) O b j ( s p l i t ) = − 2 1 j = 1 ∑ t H L + λ G L 2 − 2 1 j = 1 ∑ t H R + λ G R 2 + γ ( T + 1 )
O b j ( n o s p l i t ) − O b j ( s p l i t ) = − 1 2 ∑ j = 1 t ( G L + G R ) 2 H L + H R + λ + γ T + 1 2 ∑ j = 1 t G L 2 H L + λ + 1 2 ∑ j = 1 t G R 2 H R + λ − γ ( T + 1 ) Obj_{(nosplit)}-Obj_{(split)}=-\frac{1}{2}\sum_{j=1}^t\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}+\gamma T+\frac{1}{2}\sum_{j=1}^t\frac{G_L^2}{H_L+\lambda}+\frac{1}{2}\sum_{j=1}^t\frac{G_R^2}{H_R+\lambda}-\gamma(T+1) O b j ( n o s p l i t ) − O b j ( s p l i t ) = − 2 1 j = 1 ∑ t H L + H R + λ ( G L + G R ) 2 + γ T + 2 1 j = 1 ∑ t H L + λ G L 2 + 2 1 j = 1 ∑ t H R + λ G R 2 − γ ( T + 1 )
= − 1 2 [ ∑ j = 1 t G R 2 H R + λ + ∑ j = 1 t G L 2 H L + λ − ∑ j = 1 t ( G L + G R ) 2 H L + H R + λ ] − γ =-\frac{1}{2}[\sum_{j=1}^t\frac{G_R^2}{H_R+\lambda}+\sum_{j=1}^t\frac{G_L^2}{H_L+\lambda}-\sum_{j=1}^t\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}]-\gamma = − 2 1 [ j = 1 ∑ t H R + λ G R 2 + j = 1 ∑ t H L + λ G L 2 − j = 1 ∑ t H L + H R + λ ( G L + G R ) 2 ] − γ
遞歸執行上式步驟,直到樹的最大的深度,然後進行剪枝,遞歸得把劃分葉子得到的Gain爲負的剪枝。
貪婪算法子樹生成的算法過程如下(不包含剪枝部分):
5)XGBOOST算法過程
下面我們看看XGBOOST具體的算法過程:
輸入:訓練數據集D = { ( x i , y i ) } i = 1 n D=\left\{ (x_i,y_i) \right\}^n_{i=1} D = { ( x i , y i ) } i = 1 n ,x i ∈ R d x_i\in R^d x i ∈ R d ,最大迭代次數T T T
輸出:強學習器h ( x ) h(x) h ( x )
f o r t = 1 , 2.... T ( 迭 代 T 次 ) : for \ t=1,2....T(迭代T次): f o r t = 1 , 2 . . . . T ( 迭 代 T 次 ) :
計算所有樣本的一階導數G j = ∑ i = 1 n g i G_j=\sum_{i =1}^n g_i G j = ∑ i = 1 n g i ,二階導數H j = ∑ i = 1 n h i H_j=\sum_{i =1}^n h_i H j = ∑ i = 1 n h i
採用貪婪法生成子樹f t ( x ) f_t(x) f t ( x ) ,計算每個葉子節點G i , H i G_i,H_i G i , H i ,並求取每個葉子節點的權重w ∗ w^* w ∗ 。
把新生成的決策樹f t ( x ) f_t(x) f t ( x ) 加入y ^ i ( t ) = y ^ i ( t − 1 ) + ϵ f t ( x i ) \hat y_i^{(t)} =\hat y_i^{(t-1)} +\epsilon f_t(x_i) y ^ i ( t ) = y ^ i ( t − 1 ) + ϵ f t ( x i ) ,其中 ϵ \epsilon ϵ 爲學習率,主要爲了控制模型的過擬合。
h ( x ) = ∑ t = 1 T f t ( x i ) h(x)=\sum_{t=1}^Tf_t(x_i) h ( x ) = ∑ t = 1 T f t ( x i )
6)XGBOOST算法總結
下面我們對XGBOOST算法的特點進行總結。
算法改進:
目標函數引入了正則項Ω ( f ) \Omega(f) Ω ( f ) ;
算法內置了交叉驗證功能;
能自動對缺失值進行處理;
可自定義目標函數,只需滿足有二階導數;
系統優化:
並行計算各個特徵的增益;
剪枝,先按照最大深度進行子樹生成,再進行遞歸剪枝;
硬件優化,通過設置合理的分塊的大小,充分利用了CPU緩存進行讀取加速;
由此可以看出,XGBOOST在GBDT上做的優化已接近極致。因此,後續微軟推出的LightGBM也是隻在內存佔用和運行速度做了不少優化。如果你使用XGBOOST算法,內存佔用和運行速度成了問題,選擇使用LightGBM是一個不錯的選擇。
下篇我們探討scikit-learn中XGBOOST的使用。
(歡迎大家在評論區探討交流,也歡迎大家轉載,轉載請註明出處!)
上篇:Scikit-learn GBDT算法庫總結與實踐
下篇:持續更新中,敬請關注