引言
XGBoost 自誕生以來,就屢次在國際機器學習大賽中摘取桂冠,風頭隱隱有超過深度學習之勢,堪稱機器學習的"大殺器"。今天我們就來揭開 XGBoost 的神祕面紗,瞧瞧它的廬山真面目。
一、XGBoost 簡介
XGBoost 跟上一篇的 AdaBoost 都屬於集成學習的範疇,即利用多個弱學習器組成最終的強學習器。
說到 XGBoost 不得不提 GBDT(Gradient Boosting Decision Tree), XGBoost 是 GBDT 思想的一種實現,把速度和性能提升到了極致,所以XGBoost 的 “X” 是 “Extreme” 的意思。
二、XGBoost 的基本思路
回想決策樹中,我們用不同的屬性劃分分支,最終每個樣本都會到達葉子節點,所以葉子節點代表了樣本的分類結果。
我們知道決策樹不僅可以解決分類問題(葉子節點代表一個類別), 也可以解決迴歸問題(葉子節點代表樣本的分值),但總體思路是一樣的。
舉個例子,比如我們要預測某個人是否喜歡玩遊戲,可以建立如下這樣一棵決策樹。
這是一個迴歸問題,每個樣本的分值等於其所在葉子節點的分值,分值正負表示是否喜歡玩遊戲,分值大小表示喜歡玩遊戲的程度。
上圖中我們用 “年齡” 屬性建立了決策樹,得出了 “age < 20” 的人喜歡玩遊戲程度爲 “+2”, “age >= 20” 的人喜歡玩遊戲的程度爲 “-1”。
但是隻用一個屬性建立的決策樹太片面了,所以我們又用 “是否每天用電腦” 建立了第二棵決策樹。
最後,我們把樣本在兩棵決策樹中分值加起來表示樣本的最後分值,例如圖中小朋友的分值爲 2 + 0.9 = 2.9,老爺爺的分值爲 -1 + (-0.9) = -1.9
總結一下,如果我們建立 K 棵樹,每個樣本 xi 的預測分值 y^i 爲該樣本在每棵決策樹葉子節點的分值之和。
y^i=t=1∑Kft(xi)
其中 ft(xi) 表示樣本 xi 第 t 棵樹中所在葉子的分值。
好了,現在思考一下:每次添加一棵新樹時,如何評判新添加的樹對總體而言是好的還是不好的?
評判標準就是:樣本 xi 的預測值 y^i 與樣本真實值 yi 之間的差異是否越來越小了。
舉個例子:在貸款額度評估模型中,樣本小王的真實貸款額度爲30萬, 我們看看什麼是好的建樹過程。
- 第一棵樹:小王所在葉子分值爲 20萬, 此時差異 ∣y^(1)−y∣=∣f1(x)−y∣=10萬
- 第二棵樹:小王所在葉子分值爲 15萬, 此時差異 ∣y^(2)−y∣=∣f1(x)+f2(x)−y∣=5萬
- 第三棵樹:小王所在葉子分值爲 -3萬, 此時差異 ∣y^(3)−y∣=∣f1(x)+f2(x)+f3(x)−y∣=2萬
可以看出,每添加一棵樹,樣本分值的和 y^(t)=∑t=1Kft(x) 與真實值 y 之間的差異都在變小。換言之,每棵新樹分值 ft(x) 的目標不是 y 本身, 而是爲了彌補之前剩下的差異 ∣y^(t−1)−y∣ 。
可以看到,預測值 y^ 等於所有決策樹的分值總和,每棵新樹 t 都在上一次分值之和 y^(t−1) 的基礎上加上自己的分值 ft,構成新的預測值。
書歸正傳,XGBoost 就是用的這種思路,每棵新樹都在逐步彌補預測值與真實值之間的差異。
現在目標清楚了,問題在於 XGBoost 是如何添加新樹使得新樹可以逐步彌補樣本差異的呢?
三、XGBoost 的原理探究
3.1 提出目標函數
現在再總結一下剛纔的過程:
- 最初沒有樹,預測值 y^(0) 爲 0
- 每添加一棵樹 ft, 預測值 y^i(t) 爲之前的預測值 y^i(t−1) 與 新樹分值 ft(xi) 之和
這是一個遞歸加和的過程, 希望大家能夠理解。
有了預測值 y^,想求 ft,需要給出我們的目標函數。
一方面,我們想讓預測值 y^ 和 真實值 y 之間的差異 loss 最小,這裏不同算法評估差異的方式不同。比如:
- 線性迴歸:loss(yi,y^i)=(yi−y^i)2
- 邏輯迴歸:loss(yi,y^i)=yiln(1+e−y^i)+(1−yi)ln(1+ey^i)
其他算法的 loss 計算方式可能又有不同,真正用哪種方式應該根據解決的具體問題而定,這裏統稱爲 l(yi,y^i)。
另一方面,爲了防止過擬合和決策樹過於複雜,我們需要爲每棵樹添加懲罰項 Ω,常用的懲罰項有以下幾種:
- L1 正則化:Ω=λ∣∣w∣∣1=λ∑i=1n∣wi∣
- L2 正則化:Ω=λ∣∣w∣∣2=21λ∑i=1nwi2
- 懲罰葉子節點個數 T: Ω=γT
其中
- λ 和 γ 爲用戶可以調節的參數
- w 爲權重,這裏就是葉子的分值
- T 表示每棵決策樹的葉子節點個數,葉子個數越多,決策樹越複雜,所以需要懲罰
在 XGBoost 中我們同時使用 L2正則化和葉子節點數作爲懲罰項 Ω:
Ω=γT+λ∣∣w∣∣2
所以我們的目標函數 Obj 等於每個樣本的 loss 之和再加上每棵樹的懲罰項之和。
Obj=i=1∑nl(yi,y^i)+t=1∑KΩ(ft)
因爲在計算第 t 棵樹時,前 t-1 棵樹已經是已知常量,所以前 t-1 棵樹的 Ω 也已經是常量,因爲常量對目標函數求梯度是沒有作用的, 所以這一部分可以統一表示爲 constant,此時目標函數變爲:
Obj=i=1∑nl(yi,y^i)+Ω(ft)+constant
接下來就是如何求解目標函數了。
3.2 求解目標函數
3.2.1 關於 ft
對於第 t 棵樹,函數 ft(xi) 表示樣本 xi 的分值,而樣本的分值等於其所在葉子節點的分值,所以 ft 可以表示爲每個葉子節點分值組成的向量,這裏葉子的分值又叫做權重,用 wj 表示。如果有 T 個葉子節點, 則 ft:
ft={w1,w2,...,wT}
對於 ft(xi),如果 xi 落到了第 3 個葉子節點上,則 ft(xi)=w3
3.2.2 loss 部分泰勒展開
對於第 t 棵樹,目標函數:
Obj(t)=i=1∑nl(yi,y^i(t))+Ω(ft)+constant
注意到 y^i(t)=y^i(t−1)+ft(xi), 所以
l(yi,y^i(t))=l(yi,y^i(t−1)+ft(xi))
注意這裏 yi 是已知的常量,變量爲 y^i(t−1)+ft(xi)
我們發現新樹 ft 相當於在原來 t-1 棵樹的基礎上加了一個增量。
而對於此類加增量的問題 f(x+Δx),可以用泰勒展開來求解。
泰勒公式二次展開:
f(x+Δx)≈f(x)+f′(x)Δx+21f′′(x)Δx
把 l(yi,y^i(t−1)) 看成 f(x), 把 y^i(t−1) 看成 x, 把 ft(xi) 看成 Δx,同時用 g 表示一階導數 f′(x), 用 h 表示二階導數 f′′(x),目標函數變爲:
Obj(t)=i=1∑n[l(yi,y^i(t−1))+gift(xi)+21hift2(xi)]+Ω(ft)+constant
又注意到目標函數中 l(yi,y^i(t−1)) 在算第 t 棵樹時也是一個常量,可以歸到 constant 中,所以目標函數變成
Obj(t)=i=1∑n[gift(xi)+21hift2(xi)]+Ω(ft)+constant
導數求解舉例
以線性迴歸爲例,loss 爲,
loss(yi,y^i(t−1))=(yi−y^i(t−1))2
- 則一階導數 gi=2(yi−y^i(t−1))
- 二階導數 hi=2
- 對於其他loss, 同理可求 gi 和 hi
3.2.3 Ω 部分化簡展開
目標函數的懲罰項部分
Ω(ft)==γT+λ∣∣wj∣∣2γT+21λi=1∑nwj2
對於圖中的決策樹,懲罰項爲:
γ3+21λ(4+0.01+1)
3.2.4 從按樣本統計到按葉子統計
因爲每個樣本的權重就是所在葉子節點的權重 w,那麼所有樣本的權重之和就等於每個葉子節點的權重乘以葉子所含樣本的個數然後再求和。
i=1∑nwi=j=1∑Twj∗dj
其中 dj 表示第 j 個葉子節點所含的樣本數。
同理, 樣本的一階導數 gi 和 二階導數 hi 也只與其所在的葉子節點有關,所以有
i=1∑ngi=j=1∑Tgj∗dj=Gj
i=1∑nhi=j=1∑Thj∗dj=Hj
這裏分別用 Gj 和 Hj 表示每個葉子節點上樣本導數的和。
代入到目標函數:
Obj(t)=i=1∑n[gift(xi)+21hift2(xi)]+Ω(ft)+constant=i=1∑n[gift(xi)+21hift2(xi)]+γT+21λj=1∑Twj2+constant=j=1∑T[Gjwj+21Hjwj2+21λwj2]+γT+constant=j=1∑T[Gjwj+21(Hj+λ)wj2]+γT+constant
這裏 ft(xi)=wj 因爲樣本的分值就是其所在的葉子節點的權重。
注意到常數項對目標函數求梯度沒有作用,可以捨棄,最終的目標函數爲:
Obj(t)=j=1∑T[Gjwj+21(Hj+λ)wj2]+γT
3.2.5 目標函數求解
目標函數中只有 wj 是變量,對目標函數求梯度計算最小值,可以得到最優的wj
wj=−Hj+λGj
有了 wj, 就有了 ft(xi),因爲
ft={w1,w2,...,wT}
此時的最優目標函數爲
Obj(t)=−21j=1∑THj+λGj2+γT
下圖例子中,5 個樣本分到了 3 個葉子節點上,計算出的目標函數越小越好。
3.3 樹的內部如何分支
至此,我們第 t 棵爲每個葉子節點求出了最佳的 wj,這有一個前提,在計算的過程中我們假設了第 t 棵樹的葉子節點數爲 T, 那麼 T 如何確定,也就是第 t 棵樹如何通過層層分支建立起來,以獲得最優的葉子節點個數 T。
這裏我們用了貪婪算法。
回想我們最初建立決策樹時用熵的變化計算分支前後的信息增益來決定如何分支,這裏我們也用類似的方式。
最優目標函數
Obj(t)=−21j=1∑THj+λGj2+γT
我們將分支前後最優目標函數的變化叫做增益。
對每一個葉節點進行分支,左分支最優目標函數:
ObjL=−21HL+λGL2+γTL
右分支最優目標函數:
ObjR=−21HR+λGR2+γTR
分支之前的葉子節點最優目標函數應該爲:
Obj=−21H+λG2+γT=−21(HL+HR)+λ(GL+GR)2+γ(TL+TR−1)
用分支前的 Obj 減去分支後的 ObjL+ObjR 作爲增益 Gain,如果 Gain > 0, 說明分支後最優目標函數減小了,那麼就應該分支。
Gain=Obj−(ObjL+ObjR)=21[HL+λGL2+HR+λGR2−(HL+HR)+λ(GL+GR)2]−γ
現在有了要不要分支,那如果需要分的話從哪裏分?比如屬性有 n 個值,那麼應該從哪裏分呢?
首先需要將 n 個屬性排序,然後嘗試從任意兩個相鄰屬性之間分支,有 n-1 種可能,我們依次計算這 n-1 種可能的每一種可能的 Gain, 最後從 Gain 最大處分支。
比如下圖中我們對"年齡"屬性進行分支,發現從 a 分支 Gain 最大,那就從 a 處分支。
四、XGBoost 一些優化點
- 快速停止
如果連續幾次的 Gain 都小於等於 0,說明分支無益,可以提前停止。
- 步長收縮
通常不直接使用 y^(t)=y^(t−1)+ft(xi),而是採用
y^(t)=y^(t−1)+ϵft(xi), 其中 ϵ 叫做步長因子或收縮因子,通常爲 0.1,這樣做是爲了不在每一步試圖全局最優,而是給未來留下優化的空間,避免過擬合。
後記
XGBoost 就聊到這裏了,作爲大殺器的存在看起來有些複雜,我盡力用通俗的語言來描述、把所有過程推導細節都給出來,希望大家可以喫透,其實理解了思路,推導起來就簡單多了。
XGBoost 是《決策樹系列》的最後一篇文章,希望這個系列對大家有所幫助,哪怕只有一丟丟也很值得我爲此開心。
好了,廢話不多說了,從下一次開始我們將聊聊《神經網絡系列》,從邏輯迴歸(LR)、深度神經網絡(DNN)到卷積神經網絡(CNN),以及每種網絡的正向傳播和反向傳播的推導,希望到時候還能和您一起,在大數據茶館邊喝茶邊聊天~
歡迎關注本人公衆號《大數據茶館》,用大白話暢聊大數據。
來的都是客,歡迎您常來坐坐~