機器學習算法總結(四)——GBDT與XGBOOST


  Boosting方法實際上是采用加法模型與前向分布算法。在上一篇提到的Adaboost算法也可以用加法模型和前向分布算法來表示。以決策樹為基學習器的提升方法稱為提升樹(Boosting Tree)。對分類問題決策樹是CART分類樹,對回歸問題決策樹是CART回歸樹。

1、前向分布算法

  引入加法模型

  

  在給定了訓練數據和損失函數$L(y, f(x))$ 的條件下,可以通過損失函數最小化來學習加法模型

  

  然而對於這個問題是個很復雜的優化問題,而且要訓練的參數非常的多,前向分布算法的提出就是為了解決模型的優化問題,其核心思想是因為加法模型是由多各模型相加在一起的,而且在Boosting中模型之間又是有先后順序的,因此可以在執行每一步加法的時候對模型進行優化,那么每一步只需要學習一個模型和一個參數,通過這種方式來逐步逼近全局最優,每一步優化的損失函數:

  

  具體算法流程如下:

  1)初始化$f_0(x) = 0$;

  2)第m次迭代時,極小化損失函數

  

  3)更新模型,則$f_m (x)$:

  

  4)得到最終的加法模型

  

  Adaboost算法也可以用前向分布算法來描述,在這里輸入的數據集是帶有權重分布的數據集,損失函數是指數損失函數。

2、GBDT算法

  GBDT是梯度提升決策樹(Gradient Boosting Decision Tree)的簡稱,GBDT可以說是最好的機器學習算法之一。GBDT分類和回歸時的基學習器都是CART回歸樹,因為是擬合殘差的。GBDT和Adaboost一樣可以用前向分布算法來描述,不同之處在於Adaboost算法每次擬合基學習器時,輸入的樣本數據是不一樣的(每一輪迭代時的樣本權重不一致),因為Adaboost旨在重點關注上一輪分類錯誤的樣本,GBDT算法在每一步迭代時是輸出的值不一樣,本輪要擬合的輸出值是之前的加法模型的預測值和真實值的差值(模型的殘差,也稱為損失)。用於一個簡單的例子來說明GBDT,假如某人的年齡為30歲,第一次用20歲去擬合,發現損失還有10歲,第二次用6歲去擬合10歲,發現損失還有4歲,第三次用3歲去擬合4歲,依次下去直到損失在我們可接受范圍內。

  以平方誤差損失函數的回歸問題為例,來看看以損失來擬合是個什么樣子,采用前向分布算法:

  

  在第$m$次迭代時,我們要優化的損失函數:

  

  此時我們采用平方誤差損失函數為例:

  

  則上面損失函數變為:

  

  問題就成了對殘差r的擬合了

  然而對於大多數損失函數,卻沒那么容易直接獲得模型的殘差,針對該問題,大神Freidman提出了用損失函數的負梯度來擬合本輪損失的近似值,擬合一個回歸樹

  

  關於GBDT一般損失函數的具體算法流程如下:

  1)初始化$f_0(x)$:

  

  2)第$m$次迭代時,計算當前要擬合的殘差$r_{mi}$:

   

  以$r_{mi}$為輸出值,對$r_{mi}$擬合一個回歸樹(此時只是確定了樹的結構,但是還未確定葉子節點中的輸出值),然后通過最小化當前的損失函數,並求得每個葉子節點中的輸出值$c_{mj}$,$j$表示第$j$個葉子節點

  

  更新當前的模型$f_m(x)$為:

  

  3)依次迭代到我們設定的基學習器的個數$M$,得到最終的模型,其中$M$表示基學習器的個數,$J$表示葉子節點的個數

  

  GBDT算法提供了眾多的可選擇的損失函數,通過選擇不同的損失函數可以用來處理分類、回歸問題,比如用對數似然損失函數就可以處理分類問題。大概的總結下常用的損失函數:

  1)對於分類問題可以選用指數損失函數、對數損失函數。

  2)對於回歸問題可以選用均方差損失函數、絕對損失函數。

  3)另外還有huber損失函數和分位數損失函數,也是用於回歸問題,可以增加回歸問題的健壯性,可以減少異常點對損失函數的影響。

3、GBDT的正則化

  在Adaboost中我們會對每個模型乘上一個弱化系數(正則化系數),減小每個模型對提升的貢獻(注意:這個系數和模型的權重不一樣,是在權重上又乘以一個0,1之間的小數),在GBDT中我們采用同樣的策略,對於每個模型乘以一個系數λ (0 < λ ≤ 1),降低每個模型對擬合損失的貢獻,這種方法也意味着我們需要更多的基學習器。

  第二種是每次通過按比例(推薦[0.5, 0.8] 之間)隨機抽取部分樣本來訓練模型,這種方法有點類似Bagging,可以減小方差,但同樣會增加模型的偏差,可采用交叉驗證選取,這種方式稱為子采樣。采用子采樣的GBDT有時也稱為隨機梯度提升樹(SGBT)。

  第三種就是控制基學習器CART樹的復雜度,可以采用剪枝正則化。

4、GBDT的優缺點

  GBDT的主要優點:

  1)可以靈活的處理各種類型的數據

  2)預測的准確率高

  3)使用了一些健壯的損失函數,如huber,可以很好的處理異常值

  GBDT的缺點:

  1)由於基學習器之間的依賴關系,難以並行化處理,不過可以通過子采樣的SGBT來實現部分並行。

 

5、XGBoost算法

  事實上對於樹模型為基學習器的集成方法在建模過程中可以分為兩個步驟:一是確定樹模型的結構,二是確定樹模型的葉子節點中的輸出值。

5.1 定義樹的復雜度

  首先把樹拆分成結構部分$q$和葉子節點輸出值$w$,在這里$w$是一個向量,表示各葉子節點中的輸出值。在這里就囊括了上面提到的兩點,確定樹結構$q$和葉子結點的輸出值$w$。從下圖中可以看出,$q(x)$實際上是確定輸入值最終會落到哪個葉子節點上,而$w$將會給出相應的輸出值。

  

  具體表現示例如下,引入正則化項 $\Omega (f_t)$來控制樹的復雜度,從而實現有效的控制模型的過擬合,這是xgboost中的第一個重要點。式子中的$T$為葉子節點數

  

5.2 XGBoost中的Boosting Tree模型

  

  和GBDT方法一樣,XGBoost的提升模型也是采用殘差,不同的是分裂結點選取的時候不一定是最小平方損失,其損失函數如下,較GBDT其根據樹模型的復雜度加入了一項正則化項:

  

5.3 對目標函數進行改寫

  

  上面的式子是通過泰勒展開式將損失函數展開為具有二階導的平方函數。

  在GBDT中我們通過求損失函數的負梯度(一階導數),利用負梯度替代殘差來擬合樹模型。在XGBoost中直接用泰勒展開式將損失函數展開成二項式函數(前提是損失函數一階、二階都連續可導,而且在這里計算一階導和二階導時可以並行計算),假設此時我們定義好了樹的結構(在后面介紹,和GBDT中直接用殘差擬合不同),假設我們的葉節點區域為:

  

  上面式子中$i$代表樣本$i$,$j$代表葉子節點$j$。

  則我們的目標優化函數可以轉換成(因為$l(y_i, y_i^{t-1})$是個已經確定的常數,可以舍去):

  

  上面式子把樣本都合並到葉子節點中了。

  此時我們對$w_j$求導並令導數為0,可得:

   

  其中 $ G_j = \sum_{i \in I_j} g_i,  H_j = \sum_{i \in T_j} h_j $。 

5.4 樹結構的打分函數

  上面的Obj值代表當指定一個樹結構時,在目標上面最多減少多少,我們可以把它稱為結構分數。可以認為這是一個類似與基尼指數一樣更一般的對樹結構進行打分的函數。如下面的例子所示

  

  對於求得Obj分數最小的樹結構,我們可以枚舉所有的可能性,然后對比結構分數來獲得最優的樹結構,然而這種方法計算消耗太大,更常用的是貪心法(事實上絕大多數樹模型都是這樣的,只考慮當前節點的划分最優),每次嘗試對已經存在的葉節點(最開始的葉節點是根節點)進行分割,然后獲得分割后的增益為:

  

  在這里以$Gain$作為判斷是否分割的條件,這里的$Gain$可以看作是未分割前的Obj減去分割后的左右Obj,因此如果$Gain < 0$,則此葉節點不做分割,然而這樣對於每次分割還是需要列出所有的分割方案(對於特征的值的個數為n時,總共有2^n - 2 種划分)。而實際中是采用近似貪心方法,我們先將所有樣本按照$g_i$從小到大排序,然后進行遍歷,查看每個節點是否需要分割(對於特征的值的個數為$n$時,總共有$n-1$種划分),具體示例如下:

  

  最簡單的樹結構就是一個節點的樹。我們可以算出這棵單節點的樹的好壞程度obj*。假設我們現在想按照年齡將這棵單節點樹進行分叉,我們需要知道:

  1)按照年齡分是否有效,也就是是否減少了obj的值

  2)如果可分,那么以哪個年齡值來分。

  此時我們就是先將年齡特征從小到大排好序,然后再從左到右遍歷分割

  這樣的分割方式,我們就只要對樣本掃描一遍,就可以分割出$G_L$,$G_R$,然后根據$Gain$的分數進行分割,極大地節省了時間。所以從這里看,XGBoost中從新定義了一個划分屬性,也就是這里的$Gain$,而這個划分屬性的計算是由其目標損失決定obj的。

5.5 XGBoost中其他的正則化方法

  1)像Adaboost和GBDT中一樣,對每一個模型乘以一個系數$\lambda(0 < \lambda ≤ 1)$,用來降低每個模型對結果的貢獻。

  2)采用特征子采樣方法,和RandomForest中的特征子采樣一樣,可以降低模型的方差

6、XGBoost和GBDT的區別

   1)將樹模型的復雜度加入到正則項中,來避免過擬合,因此泛化性能會由於GBDT。

   2)損失函數是用泰勒展開式展開的,同時用到了一階導和二階導,可以加快優化速度。

  3)和GBDT只支持CART作為基分類器之外,還支持線性分類器,在使用線性分類器的時候可以使用L1,L2正則化。

  4)引進了特征子采樣,像RandomForest那樣,這種方法既能降低過擬合,還能減少計算。

  5)在尋找最佳分割點時,考慮到傳統的貪心算法效率較低,實現了一種近似貪心算法,用來加速和減小內存消耗,除此之外還考慮了稀疏數據集和缺失值的處理,對於特征的值有缺失的樣本,XGBoost依然能自動找到其要分裂的方向。

  6)XGBoost支持並行處理,XGBoost的並行不是在模型上的並行,而是在特征上的並行,將特征列排序后以block的形式存儲在內存中,在后面的迭代中重復使用這個結構。這個block也使得並行化成為了可能,其次在進行節點分裂時,計算每個特征的增益,最終選擇增益最大的那個特征去做分割,那么各個特征的增益計算就可以開多線程進行。


免責聲明!

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



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