筆記(總結)-XGBoost的前世今生

現今的各類數據挖掘比賽中,決策樹模型佔據了半壁江山(另外半壁基本就是神經網絡模型)。決策樹,本質上來說就是通過一系列的“規則”將樣本集不斷劃分歸類,最後歸爲同一類的樣本被認爲是相似的,賦予相同的預測值。

決策樹相對於其他機器學習模型來說:

  1. 可解釋較強(規則劃分)
  2. 能夠有合理的調參依據(樹深度、葉子節點個數等參數概念都很直觀)
  3. 適用於bagging和boosting方式的建模(Random Forest、Adaboost、GBDT等)
  4. 有高效的並行化實現(XGBoost、LightGBM等)

本文主要圍繞XGBoost進行闡述,在網上查閱過很多博客,各有亮點,但總是看完之後還帶有一些疑問。閱讀了原作者的論文和講解PPT後,總結相關概念,將思路過程記錄下來。


拆解XGBoost概念如下

什麼是XGBoost?

XGBoost是華盛頓大學陳天奇開發的開源工具包,是GBDT的高效實現,同時加入了適當改進。

什麼是GBDT?

GBDT(Gradient Boosting Decision Tree)。GBDT有很多簡稱,有GBT(Gradient Boosting Tree), GTB(Gradient Tree Boosting ), GBRT(Gradient Boosting Regression Tree), MART(Multiple Additive Regression Tree),其實都是指的同一種算法。

什麼是Boosting?

Boosting是一類將弱學習器提升爲強學習器的算法框架。從初始樣本中訓練出一基學習器,根據訓練結果對訓練過程做出調整,調整過後再重新訓練另一學習器,不斷重複這個過程,最終把所有學習器的預測結果加權結合。

什麼是Decision Tree?

Decision Tree(決策樹)是一類通過規則將樣本集不斷進行劃分的算法。初始時,所有樣本都屬於根節點。根據規則,將樣本分爲兩撥,分別劃分到根節點下屬的兩個節點中,重複這個過程直到劃分結束。最後可能得到一棵不規則的二(多)叉樹。葉子節點中的樣本被認爲是相似的,將根據某一依據賦予相同的預測值。


由最底層概念Decision Tree開始,逐步改善得到XGBoost

決策樹做分類

以二分類問題(人是否喜歡上網)爲例。根節點時,選擇能描述樣本集(不同的人)的某一屬性(年齡),不同樣本具有不同的屬性值,根據某一屬性值(25歲)能將樣本分成兩撥(25歲以上或以下)。重複這個過程,直到產生所有葉子節點(滿足節點分裂停止條件,如樹的深度達到最大限制等)。每個葉子節點中有很多樣本,利用投票機制來決定該節點是不是喜歡上網的人羣(共18人,12人喜歡,6人不喜歡,則該節點爲喜歡上網人羣)。對於未知的人,將其按特徵不斷劃分,最終落到葉子節點中,根據該節點之前的標記來預測該人是否喜歡上網。

在分裂節點時,如何選擇合適的屬性和劃分的屬性值呢?我們希望分裂過後,能將上網的人和不上網的人儘量區分開。例如,規則A將20人(10人喜歡上網、10人不喜歡)分爲S1 10人、S2 10人兩撥。S1中5個人喜歡上網,5人不喜歡,S2也是如此。那麼這樣對“是否喜歡上網”這一問題的解決毫無幫助。爲了衡量這個標準,可以利用Gini係數和熵來衡量,在此不做展開。

決策樹做迴歸

迴歸問題的待預測值是連續的,最終劃分到每個葉子節點中的樣本可能具有完全不同的標籤(如15歲、20歲、25歲),此時不再滿足投票機制。改爲取所有樣本標籤的平均值作爲該節點的預測值(20歲)。在節點劃分時,Gini係數和熵也無法衡量連續情況下劃分的好壞,改爲使用均方誤差(樣本標籤平均值作爲預測)的方式,使得分裂後節點的均方誤差最小。

Boosting Decision Tree

考慮每輪決策樹來擬合樣本殘差(殘差=真實值-預測值)。假設預測年齡的迴歸問題,某樣本爲30歲,第一輪預測值爲24歲。如果是AdaBoost,則會調整該樣本權重,在下一輪中着重預測該樣本,最後將樹的預測結果加權求和。我們不這麼做,將下一輪該樣本的預測目標改爲30-24=6歲,即下一輪樣本標籤發生了變化,不再是原有標籤,而是殘差。若下一輪預測值爲4歲,則再下一輪預測目標改爲30-(24+4)=2歲。當待預測目標不斷減小接近0時,我們就可以近乎完美地預測該樣本,預測值=24+4+…近似等於預測目標。

Gradient Boosting Decision Tree

結合機器學習中常用的梯度下降的思想重新來看這個問題。給定特定的優化目標函數L,我們想要針對變量α進行優化,求得L關於α的梯度即可更新α。在Boosting Decision Tree中,目標函數其實就是衡量預測值和真實標籤的損失函數,我們實際上是想要對預測值進行不斷優化,達到減小損失函數的目的。這樣看來可以運用梯度下降的思想。當Boosting Decision Tree中使用平方誤差作爲樣本損失L時,對於預測值f(x)求梯度得到的正是殘差(如下圖所示),此時將殘差作爲下一顆樹的標籤,相當於對L關於f(x)的梯度進行擬合,最終將不同樹的結果求和,則相當於進行了變相的梯度下降!上述f(x)可以看做之前輪數預測結果的求和(24+4=28歲),是關於樣本x的預測函數,因此GBDT也可以看做函數空間的梯度下降。


此時我們得到了GBDT的核心思想:用損失函數關於之前輪預測值的負梯度來近似本輪損失。利用負梯度作爲標籤來擬合本輪的決策樹。算法如下:

這裏寫圖片描述

  1. 初始化預測函數
  2. M輪建樹過程,每輪對於每個樣本求損失函數關於之前預測值f(x)的負梯度,作爲本輪決策樹的擬合目標
  3. 求得本輪決策樹的葉子節點的待預測值γ,使得f(x)+γ的新預測值能最小化損失函數
  4. 更新預測值f(x)=f(x)+γ

可以看到,目標函數是對預測函數求導,即函數空間的梯度下降。

XGBoost

XGBoost是GBDT的高效並行實現,還加入了一些算法上的改進。這個改變過程不是一蹴而就的,原作者也是借鑑了前人的很多思想。本人水平有限,就不再敘述這個演進過程,而是直接結合原作者的slides直接給出XGBoost的邏輯框架。

對於機器學習問題,我們一般會分析樣本集的分佈特點,總結其與待預測值之間的關係,構造一個目標函數。通過優化目標函數從而達到逐步構建模型的目的。通常目標函數結構如下:

這裏寫圖片描述
其中Training Loss也叫“經驗風險”(empirical risk),用於描述模型與數據的契合程度。Regularization爲“正則化項”,也稱爲“結構風險”(structural risk),用於描述模型的複雜度。我們想最小化該目標函數,既想模型能較好地擬合訓練數據,在訓練集上偏差(bias)較小,又想得到一個複雜度低的模型。

對於GBDT,我們可以看到,算法中的目標函數只有Training Loss。考慮補充正則化項,假設GBDT由k棵樹構成,得到XGBoost的目標函數如下:

這裏寫圖片描述
前一項衡量模型在n個樣本點上的訓練誤差,後一項衡量所有樹的模型複雜度。再結合boosting將預測函數寫開,可以得到第t輪和前一輪迭代關係:

這裏寫圖片描述
在第t輪中,我們需要確定的是f函數,f和前t-1輪預測函數求和後能最小化目標函數:

這裏寫圖片描述
這樣我們可以得到第t輪的目標函數如下:

這裏寫圖片描述
結合GBDT的算法,在第t輪中,我們是用目標函數(損失函數)對預測函數的負梯度,作爲樣本標籤來擬合本輪的決策樹。XGBoost中使用一階偏導(即梯度)和二階偏導來擬合,原論文沒有提及這麼做的原因,不過根據泰勒公式:

這裏寫圖片描述
二階展開比一階展開具有更好的逼近效果。上式中的x 相當於y^(t1) ,而Δx 則相當於ft(xi) ,由此將第t輪的目標函數轉化爲:

這裏寫圖片描述
其中gihi 分別爲一階、二階導數:
這裏寫圖片描述

只保留目標函數中跟第t輪有關的項,去除常數項和前t-1輪的預測誤差,目標函數變爲:

這裏寫圖片描述
對於決策樹來說,ft(xi) 實際上是一個簡單的映射函數,對每個樣本給出預測值,決策樹中就是葉子節點最後的預測值:

這裏寫圖片描述
上式中,w 是每個葉子節點的估計值,q 是一個簡單的對應關係,把每個樣本映射到對應的葉子節點。上圖是對ft(xi) 的一個形象說明。

對於目標函數中的模型複雜度,不使用常見的L2L1 正則項,針對決策樹的特殊結構定義模型複雜度如下:

這裏寫圖片描述
T 是葉子節點個數,wj 是每個葉子節點的預測值。

到目前爲止,目標函數是以樣本爲單位進行組織,將其轉化爲以葉子節點進行組織:
這裏寫圖片描述
其中Ij 是第j 個葉子節點中包含的所有樣本的下標集合。可以看到上式實際上是T 個關於w 的二次函數和。對二次函數求解最優有:
這裏寫圖片描述
轉換目標函數表示方式:

這裏寫圖片描述
其中:
這裏寫圖片描述
由此,當給定我們樹的結構(q(x) 即每個樣本屬於哪個葉子節點),每個葉子節點的預測值可以通過解上述二次函數得到:

這裏寫圖片描述

可以看到,XGBoost將目標函數進行二階泰勒展開並進行一系列的變換,最終表示成了關於葉子節點預測值的二次函數。而求解這個二次函數所使用到的參數則是我們在最初計算的一階偏導、二階偏導。傳統的GBDT,是先計算出一階偏導作爲標籤,然後用決策樹來進行擬合,葉子節點預測值是由最終葉子節點中所有節點的標籤平均得到的。XGBoost將待預測值作爲目標函數的變量進行優化求解,更爲直接。

下面我們來具體分析構建一棵樹的過程。由上可得,給定一棵樹的結構,可以求得最優葉子節點預測值和目標函數最小值。枚舉樹的結構是不現實的,每一步分裂節點時可以考慮各類特徵、每個特徵的分裂點等,導致樹的結構幾乎是無窮多。一般來說,是採用貪心的做法。在當前節點,選取增益最大的方式進行分裂。雖然這樣可能無法達到全局最優,但是也算是有限算力下的最好辦法了。貪心分裂在原作者slides裏說的很清楚:

這裏寫圖片描述
分裂增益實際上就是分裂前後目標函數的差值,可以看到在最後還減去了衡量葉子節點個數複雜度的參數γ,此處表示多引入一個葉子節點所增加的模型複雜度的開銷(原來的一個葉子節點分裂變成左右兩個葉子節點),這種做法實際上是限制了節點的分裂,減少了過擬合的可能性。

對於待分裂節點,遍歷每個屬性。針對每個屬性,將樣本按屬性值大小排序。任意屬性值都能將樣本劃分爲兩部分,掃描一遍樣本,計算每個劃分點的GLGR ,即可找到最佳分裂點。在XGBoost中,還採取了類似Random Forest中列採樣(column subsampling)的方式,不遍歷每個屬性,而是從中隨機抽取一部分進行計算,最終選擇增益最大的屬性。

總結算法,對於每一輪迭代:

  1. 計算所有樣本的一階偏導、二階偏導。
  2. 對於待分裂節點,貪心地選擇最佳分裂點。
  3. 達到分裂停止條件時停止分離。
  4. 將本輪得到的預測函數添加到之前輪數的預測函數上。

其中第4步中,通常採取以下改進方式:

這裏寫圖片描述
其中ϵ 表示步長(step-size or shrinkage),這表示我們只將本輪得到的結果的一部分加到預測函數中,減少了過擬合,同時更多地保留在後面輪數中發掘信息的可能性。


至此XGBoost的算法部分基本講完了。可以看到,從最初的決策樹到最後的XGBoost,改變是巨大的,同時很多改變都有着來自其他算法精華的指導思想作爲支撐。相比於GBDT,XGBoost在算法上沒有巨大改變(相比於決策樹和Boosting結合,GBDT使用函數負梯度擬合來說),但其在工程上的高效並行實現,使得該算法能真正成爲“老少咸宜”的工具,廣泛使用於各類場景。在海量數據下,快速高效的算法能壓縮迭代週期,使得調試的代價變低,極大地提高生產效率,而XGBoost不僅達到了速度上的巨大飛躍,也在算法上做了諸多改善,真正做到了精準、高效。

參考鏈接之前的筆記總結了:
筆記-GBDT&Xgboost

同時還參考了原作者陳天奇的論文和slides,有條件的話還是建議大家能閱讀原論文,對於XGBoost的理解最爲直觀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章