圖解機器學習 | XGBoost模型詳解


showmeai研究中心

作者:韓信子@ShowMeAI
教程地址https://www.showmeai.tech/tutorials/34
本文地址https://www.showmeai.tech/article-detail/194
聲明:版權所有,轉載請聯系平台與作者並注明出處

引言

XGBoost是eXtreme Gradient Boosting的縮寫稱呼,它是一個非常強大的Boosting算法工具包,優秀的性能(效果與速度)讓其在很長一段時間內霸屏數據科學比賽解決方案榜首,現在很多大廠的機器學習方案依舊會首選這個模型。

XGBoost在並行計算效率、缺失值處理、控制過擬合、預測泛化能力上都變現非常優秀。本文我們給大家詳細展開介紹XGBoost,包含「算法原理」和「工程實現」兩個方面。

關於XGBoost的工程應用實踐,歡迎大家參考ShowMeAI的另外一篇實戰文章 XGBoost工具庫建模應用詳解

(本篇XGBoost部分內容涉及到機器學習基礎知識、決策樹/回歸樹/GBDT算法,沒有先序知識儲備的寶寶可以查看ShowMeAI的文章 圖解機器學習 | 機器學習基礎知識決策樹模型詳解回歸樹模型詳解)及圖解機器學習 | GBDT模型詳解)。

1.算法原理可視化解讀

關於XGBoost的原理,其作者陳天奇本人有一個非常詳盡的Slides做了系統性的介紹,我們在這里借助於這個資料給大家做展開講解。

1)監督學習中的一些重要概念

在開始介紹Boosted Tree之前,我們先來回顧一下機器學習中的一些重要的概念。

(1)監督學習核心要素

符號(Notations):\(x_i \in R^d\) 表示訓練集中的第 \(i\) 個樣本。

模型(Model):對於已知的 \(x_i\) 如何預測 \(\hat{y}_i\)

線性模型(Linear Model) \(\hat{y}_{i}=\Sigma_{j} w_{j} x_{ij}\)(包括線性回歸和邏輯回歸),預測值 \(\hat{y}_i\)根據不同的任務有不同的解釋:

  • 線性回歸(Linear Regression): \(\hat{y}_i\)表示預測的分數。

  • 邏輯回歸(Logistic Regression): \(1/(1+e^{-\hat{y}_i})\)預測了實例為正的概率。

  • 其他:例如在排名任務中 \(\hat{y}_i\)可以是排名分數。

參數(Parameters):需要從數據中學習的東西。

  • 線性模型(Linear Model):$ \Theta =\{w_j|j=1,2,\dots,d\} $

目標函數(Objective function) \(Obj(\Theta )=L(\Theta )+\Omega (\Theta )\)

  • \(L(\Theta )\)代表訓練損失函數(Training Loss),表示模型多好的擬合了訓練數據。

  • \(\Omega (\Theta )\)為正則化項(Regularization)衡量了模型的復雜程度。

訓練數據損失函數(Training Loss) \(L=\Sigma_{i=1}^{n}l(y_i,\hat{y}_i)\)

  • 平方損失(Square Loss): \(l(y_i,\hat{y}_i)=(y_i-\hat{y}_i)^2\)

  • 邏輯損失(Logistic Loss): \(l(y_i,\hat{y}_i)=y_iln(1+e^{-\hat{y}_i})+(1-y_i)ln(1+e^{\hat{y}_i})\)

正則化項(Regularization):描述了模型的復雜程度。

  • L1 Norm(lasso)\(\Omega (w)=\lambda||w||_1\)

  • L2 Norm\(\Omega (w)=\lambda||w||^2\)

(2)監督學習進階知識

Ridge回歸\(\Sigma_{i=1}^{n}(y_i-w^Tx_i)^2+\lambda||w||^2\)

  • Ridge是線性模型(Linear Model),用的是平方損失(Square Loss),正則化項是L2 Norm。

Lasso\(\Sigma_{i=1}^{n}(y_i-w^Tx_i)^2+\lambda||w||_1\)

  • Lasso是線性模型(Linear Model),用的是平方損失(Square Loss),正則化項是L1 Norm。

邏輯回歸(Logistic Regression): \(\Sigma_{i=1}^{n}(y_iln(1+e^{-w^Tx_i})+(1-y_i)ln(1+e^{w^Tx_i}))+\lambda||w||^2\)

  • 邏輯回歸是線性模型(Linear Model),用的是邏輯損失(Logistic Loss),正則化項是L2 Norm。

(3)目標函數及偏差方差權衡

回顧一下目標函數 \(Obj(\Theta )=L(\Theta )+\Omega (\Theta )\),為什么目標函數需要兩部分組成呢?

  • 優化訓練損失函數(Training Loss)有助於建立預測模型,很好地擬合訓練數據至少能讓你更接近潛在的訓練數據的分布。

  • 優化正則化項(Regularization)有助於建立簡單的模型:模型越簡單,未來預測的方差越小,預測越穩定。

2)回歸樹(Regression Tree)和集成(Ensemble)

(1)回歸樹(Regression Tree)

回歸樹,也就是分類回歸樹(Classification and Regression Tree)(詳情請查看ShowMeAI文章回歸樹模型詳解

  • 決策規則和決策樹一樣
  • 每個葉子結點有一個值

(2)回歸樹集成(Regression Tree Ensemble)

從上圖的左圖可以看出,共有5個訓練樣本。

從上圖的中圖可以看出,每個葉子節點都有預測值:第一個葉子結點的預測值是2,第二個葉子結點的預測值是0.1,第三個葉子結點的預測值是-1。

  • 小男孩被分到第一個葉子結點中,所以小男孩的預測值是2;
  • 小女兒被分到第二個葉子結點,她的預測值是0.1;
  • 剩余的三個人(樣本)被分到第三個葉子結點中,他們的值都是-1。

最終的預測值就是樣本在每顆樹中所在的葉子結點的預測值的和。

(3)樹集成方法

樹集成的方法使用非常廣泛,像GBM、隨機森林等(詳見ShowMeAI文章 圖解機器學習 | GBDT模型詳解圖解機器學習 | 隨機森林分類模型詳解)。多達半數的數據挖掘競賽通過使用各種各樣的樹集成方法而獲勝。

  • 不受輸入量綱的影響,因此不需要對特性進行細致的標准化。
  • 學習特征之間的高階交互(高階交叉特征)。
  • 可以擴展,用於不同的行業。

(4)Boosted Tree的模型和參數

模型:假設我們有K棵樹: \(\hat{y}_i=\Sigma_{k=1}^Kf_k(x_i), f_k\in F\)。其中,F為包含所有回歸樹的函數空間。

  • 回歸樹是一個將屬性映射到分數的函數。

參數:包括每棵樹的結構和葉子結點中的分數。或者使用函數當作參數: \(\Theta =\left\{f_1,f_2,…,f_K\right\}\)

  • 這里我們不學習 \(R^d\)的權重,我們在Boosted Tree中學習函數(樹)。

(5)在單變量上學習Boosted Tree

單變量也就是單個特征,通過了解如何在單變量上學習Boosted Tree,我們可以對Boosted Tree的學習模式有個簡單的概念。

舉例:假設回歸樹只有一個輸入變量t(時間),希望預測小哥在t時刻有多喜歡浪漫音樂

從上左圖可以看到,這位小哥在單身的時候,對浪漫音樂的喜歡程度很低;但是當他遇到了女朋友,隨着體內荷爾蒙的分布增加,他對浪漫音樂的喜歡程度增加了;但是有一天分手了,他對浪漫音樂的喜歡程度又變低了。當然,我們也可以發現,上右圖的回歸樹很容易能表達上左圖。

為了構建上右圖的樹,我們需要學習兩個東西:

  • 1、分裂的點;
  • 2、每個分段上的高。

單變量回歸樹的目標(階躍函數)

  • 訓練損失:函數如何擬合點?
  • 正則化:如何定義函數的復雜度?(分裂點的個數和每段高度的L2 Norm?)

  • 圖(1)是小哥在每個時間上對浪漫音樂的喜歡程度的散點圖;
  • 圖(2)可以看到有太多的分割,模型的復雜度很高,所以模型的 \({ \Omega (f)}\)很高;
  • 圖(3)可以看到模型的擬合程度很差,所以 \({L (f)}\)很高;
  • 圖(4)是最好的,無論是擬合程度和復雜程度都非常合適;

(6)一般情形的Boosted Tree

首先回顧上面我們對Boosted Tree的定義:

模型:假設我們有K棵樹: \(\hat{y}_i = \Sigma_{k=1}^{K} f_k(x_i), f_k\in F\)

目標函數\(Obj=\Sigma_{i=1}^nl(y_i,\hat{y}_i)+\Sigma_{k=1}^K\Omega (f_k)\)

  • \(\Sigma_{i=1}^nl(y_i,\hat{y}_i)\)是成本函數

  • \(\Sigma_{k=1}^K\Omega (f_k)\)是正則化項,代表樹的復雜程度,樹越復雜正則化項的值越高(正則化項如何定義我們會在后面詳細說)。

當我們討論樹的時候,通常是啟發式的:

  • 通過信息增益來做分裂
  • 修剪樹木
  • 最大深度
  • 平滑葉值

大多數啟發式算法都能很好地映射到目標函數,采用形式(目標)視圖讓我們知道我們正在學習什么:

  • 信息增益 → 訓練損失
  • 修剪 → 對節點的正則化
  • 最大深度 - 函數空間上的約束
  • 平滑葉片值 - L2正則化對葉片的權重

回歸樹集成定義了如何得到預測值,它不僅僅可以做回歸,同樣還可以做分類和排序。具體做什么任務依賴於「目標函數」的定義:

  • 使用平方誤差:可以得到用於回歸問題的gradient boosted machine。

  • 使用對數損失:可以得到LogitBoost用於分類。

3)Gradient Boosting(如何學習)

在這一節中我們將正式學習Gradient Boosting。這里,xgboost的處理大家可以對比GBDT模型(可參考ShowMeAI文章 圖解機器學習 | GBDT模型詳解)來理解核心差異。

(1)解決方案

目標函數\(Obj=\Sigma_{i=1}^nl(y_i,\hat{y}_i)+\Sigma_{k=1}^K\Omega (f_k)\)

在做GBDT的時候,我們沒有辦法使用SGD,因為它們是樹,而非數值向量——也就是說從原來我們熟悉的參數空間變成了函數空間。

  • 參數空間:學習模型中的權重。

  • 函數空間:學習函數 \(f\),包括函數的結構和其中的權重。

解決方案:初始化一個預測值,每次迭代添加一個新函數( \(f\)):

\[\begin{aligned} \hat{y}_i^{(0)} & = 0 \\ \hat{y}_i^{(1)} & = f_1(x_i)=\hat{y}_i^{(0)}+f_1(x_i) \\ \hat{y}_i^{(2)} & = f_1(x_i)+f_2(x_i)=\hat{y}_i^{(1)}+f_2(x_i) \\ \dots \\ \hat{y}_i^{(t)} & = \Sigma_{k=1}^tf_k(x_i)=\hat{y}_i^{(t-1)}+f_t(x_i) \\ \end{aligned} \]

  • \(\hat{y}_i^{(t)}\)是第 \(t\)次迭代的預測值。

  • \(\hat{y}_i^{(t-1)}\)\(t-1\)次迭代的預測值。

  • \(f_t(x_i)\)是第 \(t\)顆樹,也就是我們第 \(t\)次迭代需要得到的樹。

(2)目標函數變換

第一步:根據上面的公式,目標函數可以做如下變形

\[\begin{aligned} Obj^{(t)} & =\Sigma_{i=1}^nl(y_i,\hat{y}_i^{(t)})+\Sigma_{k=1}^t\Omega (f_k)\\ & =\Sigma_{i=1}^nl(y_i,\hat{y}_i^{(t-1)}+f_t(x_i))+\Omega (f_t)+constant \end{aligned} \]

這里我們考慮平方損失,此時目標函數又可以變形為:

\[Obj^{(t)}=\Sigma_{i=1}^n(2(y_i-\hat{y}_i^{(t-1)})f_t(x_i)+f_t(x_i)^2)+\Omega (f_t)+constant \]

第二步:所以我們的目的就是找到 \(f_t\)使得目標函數最低。然而,經過上面初次變形的目標函數仍然很復雜,目標函數會產生二次項。

在這里我們引入泰勒展開公式:

\[f(x+\Delta x)\simeq f(x)+f(x)\Delta x+1/2f(x)\Delta x^2 \]

  • \(f(x)=\Sigma_{i=1}^nl(y_i,\hat{y}_i^{(t)})\)

  • \(\Delta x=f_t\)

目標函數利用泰勒展開式就可以變成:

\[Obj^{(t)}\simeq \Sigma_{i=1}^n(l(y_i,\hat{y}_i^{(t-1)})+g_if_t(x_i)+1/2h_if_t(x_i)^2)+\Omega (f_t)+constant \]

  • \(g_i = \partial _{\hat{y}^{(t-1)}}l(y_i,\hat{y}^{(t-1)})\)

  • \(h_i = \partial _{\hat{y}^{(t-1)}}^2l(y_i,\hat{y}^{(t-1)})\)

第三部:把常數項提出來,目標函數可以簡化為

\[Obj^{(t)}\simeq \Sigma_{i=1}^n[g_if_t(x_i)+1/2h_if_t(x_i)^2]+\Omega (f_t)+constant \]

思考:為什么要做這么多變化而不直接生成樹?

  • 理論好處:知道我們在學習什么,收斂。

  • 工程好處:回顧監督學習的要素。

    • \(g_i, h_i\)都來自損失函數的定義。

    • 函數的學習只通過 \(g_i, h_i\)依賴於目標函數。

    • 當被要求為平方損失和邏輯損失實現Bootsted Tree時,可以考慮如何分離代碼模塊。

(3)重新定義樹

在前面,我們使用 \(f_t(x)\)代表一顆樹,在本小節,我們重新定義一下樹:我們通過葉子結點中的分數向量和將實例映射到葉子結點的索引映射函數來定義樹:(有點兒抽象,具體請看下圖)

\[f_t(x)=w_q(x), w\in R^T, q:R^d\rightarrow \left\{1,2,3,…,T\right\} \]

  • \(w\)代表樹中葉子結點的權重

  • \(q\)代表的是樹的結構

從上圖可以看出,共有3個葉子結點,第一個葉子結點的權重為+1,第二個葉子結點的權重為0.1,第三個葉子結點的權重為-1;其中,小男孩屬於第1個葉子結點,老奶奶屬於第3個葉子結點。

(4)定義樹的復雜程度

通過下面的式子定義樹的復雜程度(定義並不是唯一的)

\[\Omega (f_t)=\gamma T+\frac{1}{2}\lambda\Sigma_{j=1}^Tw_j^2 \]

  • \(\gamma T\)代表了葉子結點的個樹

  • \(\frac{1}{2}\lambda\Sigma_{j=1}^Tw_j^2\)葉子結點分數的L2 Norm

(5)重新審視目標函數

定義在葉子結點 \(j\)中的實例的集合為:

\[I_j=\left\{i|q(x_i)=j \right\} \]

根據每棵葉子重新定義目標函數:

\[\begin{aligned} Obj^{(t)}& \simeq \Sigma_{i=1}^n[g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2]+\Omega (f_t)+constant \\ & = \Sigma_{i=1}^n[g_iw_q(x_i)+\frac{1}{2}h_iw_q(x_i)^2]+\gamma T+\frac{1}{2}\lambda\Sigma_{j=1}^Tw_j^2+constant \\ & = \Sigma_{j=1}^T[(\Sigma_{i\epsilon I_j} g_i)w_j+\frac{1}{2}(\Sigma_{i\epsilon I_j} h_i+\lambda)w_j^2]+\gamma T+constant \end{aligned} \]

  • 上式是T個獨立二次函數的和

(6)計算葉子結點的值

一些知識需要先了解。對於一元二次函數: \(Gx+\frac{1}{2}Hx^2\),我們很容易得到這個函數的最小值和最小值對應的 \(x\)

  • 最小值對應的 \(x\)相當於求 \(Gx+\frac{1}{2}Hx^2\)的導數,使導數等於0時的值,即 \(Gx+Hx=0\),所以 \(x=-G/H\)

  • \(x=-G/H\),對應的 \(Gx+\frac{1}{2}Hx^2\)的值為: \(-\frac{1}{2}*G^2/H\)

也就是:

\[\begin{aligned} argmin_x Gx+\frac{1}{2}Hx^2 & =-\frac{G}{H}, H>0 \\ min_x Gx+\frac{1}{2}Hx^2 & =-\frac{1}{2}\frac{G^2}{H} \end{aligned} \]

如何求葉子結點最優的值?接着繼續變化目標函數:

  • 定義 \(G_j= \Sigma_{i\epsilon I_j}g_i\)

  • 定義 \(H_j = \Sigma_{i\epsilon I_j}h_i\)

\[\begin{aligned} Obj^{(t)}&= \Sigma_{j=1}^T[(\Sigma_{i\epsilon I_j} g_i)w_j+\frac{1}{2}(\Sigma_{i\epsilon I_j} h_i+\lambda)w_j^2]+\gamma T+constant\\ & = \Sigma_{j=1}^T[G_jw_j+\frac{1}{2}(H_j+\lambda)w_j^2]+\gamma T+constant \end{aligned} \]

假設樹的結構 \(q(x)\)是固定的,那么每一個葉子結點的權重的最優值

\[w_j^*=-G_j/(H_j+\lambda) \]

目標函數的最優值

\[Obj=-\frac{1}{2}\Sigma_{j=1}^T\frac{G_j^2}{H_j+\lambda}+\gamma T \]

下圖是前面公式講解對應的一個實際例子。

這里再次總結一下,我們已經把目標函數變成了僅與 \(G、H、\gamma、\lambda、T\)這五項已知參數有關的函數,把之前的變量 \(f_{t}\)消滅掉了,也就不需要對每一個葉子進行打分了!
那么現在問題來,剛才我們提到,以上這些是假設樹結構確定的情況下得到的結果。但是樹的結構有好多種,我們應該如何確定呢?

(7)貪婪算法生成樹

上一部分中我們假定樹的結構是固定的。但是,樹的結構其實是有無限種可能的,本小節我們使用貪婪算法生成樹:

  • 首先生成一個深度為0的樹(只有一個根結點,也叫葉子結點)

  • 對於每棵樹的每個葉子結點,嘗試去做分裂(生成兩個新的葉子結點,原來的葉子結點不再是葉子結點)。在增加了分裂后的目標函數前后變化為(我們希望增加了樹之后的目標函數小於之前的目標函數,所以用之前的目標函數減去之后的目標函數):

\[Gain=\frac{1}{2}(\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda})-\gamma \]

  • \(\frac{G_L^2}{H_L+\lambda}\)是左面葉子結點的值

  • \(\frac{G_R^2}{H_R+\lambda}\)是右面葉子結點的值

  • \(\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}\)是未分裂前的值

  • \(\gamma\)是引入了多一個的葉子結點增加的復雜度

接下來要考慮的是如何尋找最佳分裂點。

例如,如果 \(x_j\)是年齡,當分裂點是 \(a\)的時候的增益gain是多少

我們需要做的僅僅只是計算每一邊的 \(g\)\(h\),然后計算

\[Gain=\frac{1}{2}(\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda})-\gamma \]

對排序后的實例進行從左到右的線性掃描就足以決定特征的最佳分裂點。

所以,分裂一個結點的方法是:

  • 對於每個節點,枚舉所有特性
  • 對於每個特性,按特性值對實例排序
  • 使用線性掃描來決定該特征的最佳分裂點
  • 采用所有特征中最好的分裂方案

時間復雜度

  • 對於一個有d個特征,深度為K的樹,計算的時間復雜度為:O(dKnlog n)。其中每一層需要花費O(nlog n)的時間做排序。

  • 可以進一步優化(例如使用近似或緩存排序的特性)。

  • 可以擴展到非常大的數據集。

(8)如何處理分類型變量

一些樹學習算法分別處理分類變量和連續變量,我們可以很容易地使用我們推導出的基於分類變量的評分公式。但事實上,我們沒有必要單獨處理分類變量:

我們可以使用one-hot方式處理分類變量:

\[z_{j}=\left\{\begin{array}{ll} 1 & \text { if } x \text { is in category } j \\ 0 & \text { otherwise } \end{array}\right. \]

如果有太多的分類的話,矩陣會非常稀疏,算法會優先處理稀疏數據。

(9)修剪和正則化

回顧之前的增益,當訓練損失減少的值小於正則化帶來的復雜度時,增益有可能會是負數:

\[Gain=\frac{1}{2}(\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda})-\gamma \]

此時就是模型的簡單性和可預測性之間的權衡。

  • 前停止(Pre-stopping):當最佳分裂是負數時,停止分裂;但是一個分裂可能會對未來的分裂有益;

  • 后剪枝(Post-Pruning):把一顆樹生長到最大深度,遞歸修剪所有分裂為負增益的葉子。

2.XGBoost核心原理歸納解析

1)目標函數與泰勒展開

XGBoost也是一個Boosting加法模型,每一步迭代只優化當前步中的子模型。
\(m\)步我們有:

\[F_m(x_i) = F_{m-1}(x_i) + f_m(x_i) \]

  • $ f_m(x_i)$為當前步的子模型。

  • $F_{m-1}(x_i) $為前 \(m-1\)個完成訓練且固定了的子模型。

目標函數設計為「經驗風險」+「結構風險」(正則項):

\[\begin{aligned} O b j &=\sum_{i=1}^{N} L\left[F_{m}\left(x_{i}\right), y_{i}\right]+\sum_{j=1}^{m} \Omega\left(f_{j}\right) \\ &=\sum_{i=1}^{N} L\left[F_{m-1}\left(x_{i}\right)+f_{m}\left(x_{i}\right), y_{i}\right]+\sum_{j=1}^{m} \Omega\left(f_{j}\right) \end{aligned} \]

  • 正則項 \(\Omega (f)\)表示子模型 \(f\)的復雜度,用於控制過擬合。

在數學中,我們可以用泰勒公式近似 \(f(x)\),具體如下式。XGBoost對損失函數運用二階展開來近似。

\[f(x_0+\Delta x) \approx f(x_0)+f^{'}(x_0) \Delta x + \frac{f^{''}(x_0)}{2} (\Delta x)^2 \]

(更多數學知識推薦閱讀ShowMeAI的AI數學基礎系列教程 圖解AI數學基礎:從入門到精通系列教程)。

對應XGBoost的損失函數,我們在上式里將 \(F_{m-1}(x_i)\)視作 \(x_0\)\(f_{m}(x_i)\)視作 \(Delta x\)\(L(\hat{y_i},y_i)\)視作關於 \(\hat{y_i}\)的函數,得到:

\[Obj = \sum_{i=1}^N \Big[ L[F_{m-1}(x_i),y_i] + \frac{\partial L}{\partial F_{m-1}(x_i)} f_m(x_i) + \frac{1}{2} \frac{\partial^2 L}{\partial^2 F_{m-1}(x_i)} f_m^2(x_i) \Big] +\sum_{j=1}^m \Omega (f_j) \]

又因前 \(m-1\)個子模型已經確定了,故上式中除了關於 \(f_{m} (x)\)的部分都是常數,不影響對 \(f_{m} (x)\)的優化求解。目標函數可轉化為:

\[O b j=\sum_{i=1}^{N}\left[g_{i} f_{m}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{m}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{m}\right) \]

  • $g_i = \frac{\partial L}{\partial F_{m-1}(x_i)} $

  • $h_i = \frac{\partial^2 L}{\partial^2 F_{m-1}(x_i)} $

  • 這里的 \(L\)代表損失函數,衡量一次預測的好壞程度

  • \(F_{m-1}(x)\)確定了的情況下,對每個樣本點 \(i\)都可以輕易計算出一個 \(g_i\)\(h_i\)

2)XGBoost的正則化

實際上,XGBoost的基分類器對決策樹和線性模型都支持,這里我們只討論更常見的「基於樹」的情況。為防止過擬合,XGBoost設置了基於樹的復雜度作為正則項:

\[\Omega(f) = \gamma T + \frac{1}{2} \lambda ||w||^2 \]

  • \(T\)為樹 \(f\)的葉節點個數

  • \(w\)為所有葉節點輸出回歸值構成的向量, \(||w||^2\)為該向量L2范數(模長)的平方

  • \(\gamma\)\(\lambda\)為超參數

作為回歸樹,葉子節點越多、輸出的回歸值越大,樹的復雜度越高。

最終目標函數如下:

\[Obj = \sum_{i=1}^N \Big[g_i f_m(x_i)+\frac{1}{2} h_i f_m^2(x_i)\Big]+\gamma T + \frac{1}{2} \lambda \sum_{j=1}^T w_j^2 \]

下面是一個數學轉換處理,為了使正則項和經驗風險項合並到一起。我們把在樣本層面上求和的經驗風險項,轉換為葉節點層面上的求和。

定義節點 \(j\)上的樣本集為 \(I(j)=\{x_i|q(x_i)=j\}\),其中 \(q(x_i)\)為將樣本映射到葉節點上的索引函數,葉節點 \(j\)上的回歸值為 \(w_j=f_m(x_i),i \in I(j)\)

\[Obj = \sum_{j=1}^{T} \Big[ (\sum_{i\in I(j)} g_i) w_j + \frac{1}{2}(\sum_{i\in I(j)} h_i + \lambda) w_j^2 \Big] + \gamma T \]

進一步簡化表達,令 \(\sum_{i\in I(j)} g_i=G_j\)\(\sum_{i\in I(j)} h_i=H_j\)注意這里G和H都是關於 \(j\)的函數:

\[Obj = \sum_{j=1}^{T} \Big[ G_j w_j + \frac{1}{2}(H_j + \lambda) w_j^2 \Big] + \gamma T \]

轉化到這個形式后,我們可以看出,若一棵樹的結構已經確定,則各個節點內的樣本 \((x_i,y_i,g_i,h_i)\)也是確定的,即 \(G_j\)\(H_j\)\(T\)被確定,每個葉節點輸出的回歸值應該使得上式最小,由二次函數極值點:

\[w_j^*=-\frac{G_j}{H_j+\lambda} \]

按此規則輸出回歸值后,目標函數值也就是樹的評分如下公式,其值越小代表樹的結構越好。觀察下式,樹的評分也可以理解成所有葉節點的評分之和:

\[Obj^* = \sum_{j=1}^T \Big( -\frac{1}{2}\frac{G_j^2}{H_j + \lambda} + \gamma \Big) \]

3)節點分裂准則

我們之前文章【決策樹模型詳解】里給大家講到了決策樹模型是遞歸生長形成的,而XGBoost的子模型樹也一樣,需要要依賴節點遞歸分裂的貪心准則來實現樹的生成。

我們之前文章決策樹模型詳解里給大家講到了決策樹模型是遞歸生長形成的,而XGBoost的子模型樹也一樣,需要要依賴節點遞歸分裂的貪心准則來實現樹的生成。

(1)貪心准則

XGBoost子樹的基本處理思路和CART一樣,會對特征值排序后遍歷划分點,將其中最優的分裂收益作為該特征的分裂收益,選取具有最優分裂收益的特征作為當前節點的划分特征,按其最優划分點進行二叉划分,得到左右子樹。

上圖是一次節點分裂過程,很自然地,分裂收益是樹A的評分減去樹B的評分。虛線框外的葉節點,即非分裂節點的評分均被抵消,只留下分裂后的LR節點和分裂前的S節點進行比較,因此分裂收益的表達式為:

\[Gain = \frac{1}{2} \Big[ \frac{G_L^2}{H_L+\lambda} + \frac{G_R^2}{H_R+\lambda} -\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}\Big]-\gamma \]

(2)近似算法

基於性能的考量,XGBoost還對貪心准則做了一個近似版本,簡單說,處理方式是「將特征分位數作為划分候選點」。這樣將划分候選點集合由全樣本間的遍歷縮減到了幾個分位數之間的遍歷。

展開來看,特征分位數的選取還有global和local兩種可選策略:

  • global在全體樣本上的特征值中選取,在根節點分裂之前進行一次即可;

  • local則是在待分裂節點包含的樣本特征值上選取,每個節點分裂前都要進行。

這兩種情況里,由於global只能划分一次,其划分粒度需要更細。

XGB原始paper中對Higgs Boson數據集進行了實驗,比較了精確貪心准則、global近似和local近似三類配置的測試集AUC,用eps代表取分位點的粒度,如 \(eps=0.25\)代表將數據集划分為1/0.25=4個buckets,發現global(eps=0.05)和local(eps=0.3)均能達到和精確貪心准則幾乎相同的性能。

XGBoost工具包支持上述提到的3類配置。

(3)加權分位數

查看目標函數 \(Obj=\sum_{i=1}^{N}\left[g_{i} f_{m}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{m}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{m}\right)\),令偏導為0易得 \(f_m^*(x_i)=-\frac{g_i}{h_i}\),此目標函數可理解為以 \(h_i\)為權重, \(-\frac{g_i}{h_i}\)為標簽的二次損失函數:

\[\begin{aligned} Obj &= \sum_{i=1}^N \Big[g_i f_m(x_i)+\frac{1}{2} h_i f_m^2(x_i)\Big]+\Omega (f_m) \\ & = \sum_{i=1}^N \frac{1}{2} h_i\Big[ f_m(x_i)-(-\frac{g_i}{h_i}) \Big]^2+\Omega (f_m) + C \end{aligned} \]

在近似算法取分位數時,實際上XGBoost會取以二階導 \(h_i\)為權重的分位數(Weighted Quantile Sketch),如下圖表示的三分位。

4)列采樣與學習率

XGBoost為了進一步優化效果,在以下2個方面進行了進一步設計:

  • 列采樣

    • 和隨機森林做法一致,每次節點分裂並不是用全部特征作為候選集,而是一個子集。
    • 這么做能更好地控制過擬合,還能減少計算開銷。
  • 學習率

    • 也叫步長、shrinkage,具體的操作是在每個子模型前(即每個葉節點的回歸值上)乘上該系數,不讓單顆樹太激進地擬合,留有一定空間,使迭代更穩定。XGBoost默認設定為0.3。

5)特征缺失與稀疏性

XGBoost也能對缺失值處理,也對特征稀疏問題(特征中出現大量的0或one-hot encoding結果)做了一些優化。XGBoost用「稀疏感知」策略來同時處理這兩個問題:

  • 簡單說,它的做法是將缺失值和稀疏0值等同視作缺失值,將其「綁定」在一起,分裂節點的遍歷會跳過缺失值的整體。這樣大大提高了運算效率。
    0值在XGB中被處理為數值意義上的0還是NA,需要結合具體平台的設置,預處理區分開作為數值的0(不應該被處理為NA)和作為稀疏值的0(應該被處理為NA)。

依然通過遍歷得到分裂節點,NA的方向有兩種情況,在此基礎上對非缺失值進行切分遍歷。

如上圖所示,若某個特征值取值為1,2,5和大量的NA,XGBoost會遍歷以上6種情況(3個非缺失值的切分點×缺失值的兩個方向),最大的分裂收益就是本特征上的分裂收益,同時,NA將被分到右節點。

3.XGBoost工程優化

1)並行列塊設計

XGBoost將每一列特征提前進行排序,以塊(Block)的形式儲存在緩存中,並以索引將特征值和梯度統計量對應起來,每次節點分裂時會重復調用排好序的塊。而且不同特征會分布在獨立的塊中,因此可以進行分布式或多線程的計算。

2)緩存訪問優化

特征值排序后通過索引來取梯度 \(g_i,h_i\)會導致訪問的內存空間不一致,進而降低緩存的命中率,影響算法效率。為解決這個問題,XGBoost為每個線程分配一個單獨的連續緩存區,用來存放梯度信息。

3)核外塊計算

數據量非常大的情形下,無法同時全部載入內存。XGBoost將數據分為多個blocks儲存在硬盤中,使用一個獨立的線程專門從磁盤中讀取數據到內存中,實現計算和讀取數據的同時進行。
為了進一步提高磁盤讀取數據性能,XGBoost還使用了兩種方法:

  • ① 壓縮block,用解壓縮的開銷換取磁盤讀取的開銷。

  • ② 將block分散儲存在多個磁盤中,提高磁盤吞吐量。

4.XGBoost vs GBDT

我們對之前講解過的GBDT(參考ShowMeAI文章【GBDT算法詳解】)和這里的XGBoost做一個對比總結:

  • GBDT是機器學習算法,XGBoost在算法基礎上還有一些工程實現方面的優化。

  • GBDT使用的是損失函數一階導數,相當於函數空間中的梯度下降;XGBoost還使用了損失函數二階導數,相當於函數空間中的牛頓法。

  • 正則化:XGBoost顯式地加入了正則項來控制模型的復雜度,能有效防止過擬合。

  • 列采樣:XGBoost采用了隨機森林中的做法,每次節點分裂前進行列隨機采樣。

  • 缺失值:XGBoost運用稀疏感知策略處理缺失值,GBDT無缺失值處理策略。

  • 並行高效:XGBoost的列塊設計能有效支持並行運算,效率更優。

更多監督學習的算法模型總結可以查看ShowMeAI的文章 AI知識技能速查 | 機器學習-監督學習

機器學習【算法】系列教程

機器學習【實戰】系列教程

ShowMeAI系列教程推薦


免責聲明!

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



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