概述
GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一種迭代的決策樹算法,該算法由多棵決策樹組成,所有樹的結論累加起來做最終答案。它在被提出之初就和SVM一起被認為是泛化能力較強的算法。
GBDT中的樹是回歸樹(不是分類樹),GBDT用來做回歸預測,調整后也可以用於分類。
集成學習==>提升方法族==>梯度提升方法==>以決策樹作為基學習器的梯度提升方法
集成學習
集成學習(ensemble learning)通過構建並結合多個學習器來完成學習任務。如何產生“好而不同”的個體學習器,是集成學習研究的核心。
根據個體學習器的生成方式,可以將集成學習方法大致分為兩大類:
- 1、個體學習器間存在強依賴關系、必須串行生成的序列化方法。
比如boosting族算法,代表性的有adaboost算法,GBDT。 - 2、個體學習器之間不存在強依賴關系、可同時生成的並行化方法。
比如bagging和“隨機森林”。
對於adaboost,bagging和隨機森林可以參考集成學習方法
Boosting
Boosting是一族可將弱學習器提升為強學習器的算法。boosting方法通過分步迭代(stage-wise)的方式來構建模型,在迭代的每一步構建的弱學習器都是為了彌補已有模型的不足。(個體學習器之間存在強依賴關系。)
boosting族算法的著名代表:AdaBoost。
AdaBoost算法通過給已有模型預測錯誤的樣本更高的權重,使得先前的學習器做錯的訓練樣本在后續受到更多的關注的方式來彌補已有模型的不足。
GBDT主要由三個概念組成:
Regression Decistion Tree(即DT),Gradient Boosting(即GB),Shrinkage (算法的一個重要演進分枝,目前大部分源碼都按該版本實現)。搞定這三個概念后就能明白GBDT是如何工作的。
一、DT:回歸樹 Regression Decision Tree
提起決策樹(DT, Decision Tree) 絕大部分人首先想到的就是C4.5分類決策樹。但如果一開始就把GBDT中的樹想成分類樹,那就錯了。千萬不要以為GBDT是很多棵分類樹。決策樹分為兩大類,回歸樹和分類樹。前者用於預測實數值,如明天的溫度、用戶的年齡、網頁的相關程度;后者用於分類標簽值,如晴天/陰天/霧/雨、用戶性別、網頁是否是垃圾頁面。這里要強調的是,前者的結果加減是有意義的,如10歲+5歲-3歲=12歲,后者則無意義,如男+男+女=到底是男是女?GBDT的核心在於累加所有樹的結果作為最終結果,就像前面對年齡的累加(-3是加負3),而分類樹的結果顯然是沒辦法累加的,所以GBDT中的樹都是回歸樹,不是分類樹,這點對理解GBDT相當重要(盡管GBDT調整后也可用於分類但不代表GBDT的樹是分類樹)。
回歸樹總體流程類似於分類樹,區別在於,回歸樹的每一個節點都會得一個預測值,以年齡為例,該預測值等於屬於這個節點的所有人年齡的平均值。分枝時窮舉每一個feature的每個閾值找最好的分割點,但衡量最好的標准不再是最大熵,而是最小化平方誤差。也就是被預測出錯的人數越多,錯的越離譜,平方誤差就越大,通過最小化平方誤差能夠找到最可靠的分枝依據。分枝直到每個葉子節點上人的年齡都唯一或者達到預設的終止條件(如葉子個數上限),若最終葉子節點上人的年齡不唯一,則以該節點上所有人的平均年齡做為該葉子節點的預測年齡。

回歸樹算法如下圖(截圖來自《統計學習方法》5.5.1 CART生成):

二、 GB:梯度迭代 Gradient Boosting
梯度提升(Gradient boosting)是一種用於回歸、分類和排序任務的機器學習技術[1],屬於Boosting算法族的一部分。Boosting是一族可將弱學習器提升為強學習器的算法,屬於集成學習(ensemble learning)的范疇。Boosting方法基於這樣一種思想:對於一個復雜任務來說,將多個專家的判斷進行適當的綜合所得出的判斷,要比其中任何一個專家單獨的判斷要好。通俗地說,就是“三個臭皮匠頂個諸葛亮”的道理。梯度提升同其他boosting方法一樣,通過集成(ensemble)多個弱學習器,通常是決策樹,來構建最終的預測模型。
Boosting、bagging和stacking是集成學習的三種主要方法。
不同於bagging方法,boosting方法通過分步迭代(stage-wise)的方式來構建模型,在迭代的每一步構建的弱學習器都是為了彌補已有模型的不足。Boosting族算法的著名代表是AdaBoost。AdaBoost算法通過給已有模型預測錯誤的樣本更高的權重,使得先前的學習器做錯的訓練樣本在后續受到更多的關注的方式來彌補已有模型的不足。
相比於AdaBoost,梯度提升方法的優點:
雖然同屬於Boosting族,但是梯度提升方法的優點比較多。
- 1、與AdaBoost算法不同,梯度提升方法在迭代的每一步構建一個能夠沿着梯度最陡的方向降低損失(steepest-descent)的學習器來彌補已有模型的不足。
- 2、經典的AdaBoost算法只能處理采用指數損失函數的二分類學習任務,而梯度提升方法通過設置不同的可微損失函數可以處理各類學習任務(多分類、回歸、Ranking等),應用范圍大大擴展。
- 3、AdaBoost算法對異常點(outlier)比較敏感,而梯度提升算法通過引入bagging思想、加入正則項等方法能夠有效地抵御訓練數據中的噪音,具有更好的健壯性。
提升樹是迭代多棵回歸樹來共同決策。當采用平方誤差損失函數時,每一棵回歸樹學習的是之前所有樹的結論和殘差,擬合得到一個當前的殘差回歸樹,殘差的意義如公式:殘差 = 真實值 - 預測值 。提升樹即是整個迭代過程生成的回歸樹的累加。GBDT的核心就在於,每一棵樹學的是之前所有樹結論和的殘差,這個殘差就是一個加預測值后能得真實值的累加量。
三、Gradient Boosting Decision Tree:梯度提升決策樹
為什么梯度提升方法傾向於選擇決策樹(通常是CART樹)作為基學習器呢?
這與決策樹算法自身的優點有很大的關系:
1、 決策樹可以認為是if-then規則的集合,易於理解,可解釋性強,預測速度快;
2、決策樹算法相比於其他的算法需要更少的特征工程,比如可以不用做特征標准化,可以很好的處理字段缺失的數據,也可以不用關心特征間是否相互依賴等
3、決策樹能夠自動組合多個特征,它可以毫無壓力地處理特征間的交互關系並且是非參數化的,因此你不必擔心異常值或者數據是否線性可分。
舉個例子,西瓜a(烏黑色、紋路清晰)可能是好瓜,西瓜b(青綠色,紋路清晰)的也可能是好瓜。決策樹一樣可以處理。
決策樹有優點,自然也有缺點,不過,可以通過梯度提升方法解決這個缺點。
單獨使用決策樹算法時,有容易過擬合缺點。怎么解決呢?
- 通過各種方法,抑制決策樹的復雜性,降低單棵決策樹的擬合能力
- 通過梯度提升的方法集成多個決策樹,則預測效果上來的同時,也能夠很好的解決過擬合的問題。
(這一點具有bagging的思想,降低單個學習器的擬合能力,提高方法的泛化能力。)
由此可見,梯度提升方法和決策樹學習算法可以互相取長補短,是一對完美的搭檔。
怎么降低單棵決策樹的復雜度?
抑制單顆決策樹的復雜度的方法有很多:
- 限制樹的最大深度、限制葉子節點的最少樣本數量、限制節點分裂時的最少樣本數量
- 吸收bagging的思想對訓練樣本采樣(subsample),在學習單顆決策樹時只使用一部分訓練樣本
- 借鑒隨機森林的思路在學習單顆決策樹時只采樣一部分特征
- 在目標函數中添加正則項懲罰復雜的樹結構等。
現在主流的GBDT算法實現中這些方法基本上都有實現,因此GBDT算法的超參數還是比較多的,應用過程中需要精心調參,並用交叉驗證的方法選擇最佳參數。
提升樹利用加法模型和前向分步算法實現學習的優化過程。當損失函數時平方損失和指數損失函數時,每一步的優化很簡單,如平方損失函數學習殘差回歸樹。
前向分布算法(Forward stagewise additive modeling)
提升方法其實是一個比adaboost概念更大的算法,因為adaboost可以表示為boosting的前向分布算法(Forward stagewise additive modeling)的一個特例,boosting最終可以表示為:

其中的w是權重,Φ是弱分類器(回歸器)的集合,其實就是一個加法模型(即基函數的線性組合)
前向分布算法實際上是一個貪心的算法,也就是在每一步求解弱分類器Φ(m)和其參數w(m)的時候不去修改之前已經求好的分類器和參數:

為了表示方便,我們以后用β代替w進行描述了,圖中的b是之前說的Φ弱分類器
OK,這也就是提升方法(之前向分布算法)的大致結構了,可以看到其中存在變數的部分其實就是極小化損失函數 這關鍵的一步了,如何選擇損失函數決定了算法的最終效果(名字)……這一步你可以看出算法的“趨勢”,以后再單獨把“趨勢”拿出來說吧,因為我感覺理解算法的關鍵之一就是理解算法公式的“趨勢”
各種提升方法
不同的損失函數和極小化損失函數方法決定了boosting的最終效果,我們現在來說幾個常見的boosting:

廣義上來講,所謂的Gradient Boosting 其實就是在更新的時候選擇梯度下降的方向來保證最后的結果最好,一些書上講的“殘差” 方法其實就是L2Boosting吧,因為它所定義的殘差其實就是L2Boosting的Derivative,接下來我們着重講一下弱回歸器是決策樹的情況,也就是GBDT。
加法模型(additive model)
GBDT算法可以看成是由K棵樹組成的加法模型:

其中F為所有樹組成的函數空間,以回歸任務為例,回歸樹可以看作為一個把特征向量映射為某個score的函數。該模型的參數為:Θ = {f 1, f 2, ... , f k} 。於一般的機器學習算法不同的是,加法模型不是學習d維空間中的權重,而是直接學習函數(決策樹)集合。上述加法模型的目標函數定義為:

如何來學習加法模型呢?
解這一優化問題,可以用前向分布算法(forward stagewise algorithm)。因為學習的是加法模型,如果能夠從前往后,每一步只學習一個基函數及其系數(結構),逐步逼近優化目標函數,那么就可以簡化復雜度。這一學習過程稱之為Boosting。具體地,我們從一個常量預測開始,每次學習一個新的函數,過程如下:

舉個例子,參考自一篇博客, 該博客舉出的例子較直觀地展現出多棵決策樹線性求和過程以及殘差的意義。
還是年齡預測,簡單起見訓練集只有4個人,A,B,C,D,他們的年齡分別是14,16,24,26。其中A、B分別是高一和高三學生;C,D分別是應屆畢業生和工作兩年的員工。如果是用一棵傳統的回歸決策樹來訓練,會得到如下圖1所示結果:

現在我們使用GBDT來做這件事,由於數據太少,我們限定葉子節點做多有兩個,即每棵樹都只有一個分枝,並且限定只學兩棵樹。我們會得到如下圖2所示結果:

在第一棵樹分枝和圖1一樣,由於A,B年齡較為相近,C,D年齡較為相近,他們被分為兩撥,每撥用平均年齡作為預測值。此時計算殘差(殘差的意思就是: A的預測值 + A的殘差 = A的實際值),所以A的殘差就是15-16=-1(注意,A的預測值是指前面所有樹累加的和,這里前面只有一棵樹所以直接是15,如果還有樹則需要都累加起來作為A的預測值)。進而得到A,B,C,D的殘差分別為-1,1,-1,1。然后我們拿殘差替代A,B,C,D的原值,到第二棵樹去學習,如果我們的預測值和它們的殘差相等,則只需把第二棵樹的結論累加到第一棵樹上就能得到真實年齡了。這里的數據顯然是我可以做的,第二棵樹只有兩個值1和-1,直接分成兩個節點。此時所有人的殘差都是0,即每個人都得到了真實的預測值。
換句話說,現在A,B,C,D的預測值都和真實年齡一致了。Perfect!:
A: 14歲高一學生,購物較少,經常問學長問題;預測年齡A = 15 – 1 = 14
B: 16歲高三學生;購物較少,經常被學弟問問題;預測年齡B = 15 + 1 = 16
C: 24歲應屆畢業生;購物較多,經常問師兄問題;預測年齡C = 25 – 1 = 24
D: 26歲工作兩年員工;購物較多,經常被師弟問問題;預測年齡D = 25 + 1 = 26
那么哪里體現了Gradient呢?其實回到第一棵樹結束時想一想,無論此時的cost function是什么,是均方差還是均差,只要它以誤差作為衡量標准,殘差向量(-1, 1, -1, 1)都是它的全局最優方向,這就是Gradient。
講到這里我們已經把GBDT最核心的概念、運算過程講完了!沒錯就是這么簡單。
該例子很直觀的能看到,預測值等於所有樹值得累加,如A的預測值 = 樹1左節點 值 15 + 樹2左節點 -1 = 14。
因此,給定當前模型 fm-1(x),只需要簡單的擬合當前模型的殘差。現將回歸問題的提升樹算法敘述如下:

1)既然圖1和圖2 最終效果相同,為何還需要GBDT呢?
答案是過擬合。過擬合是指為了讓訓練集精度更高,學到了很多”僅在訓練集上成立的規律“,導致換一個數據集當前規律就不適用了。其實只要允許一棵樹的葉子節點足夠多,訓練集總是能訓練到100%准確率的(大不了最后一個葉子上只有一個instance)。在訓練精度和實際精度(或測試精度)之間,后者才是我們想要真正得到的。
我們發現圖1為了達到100%精度使用了3個feature(上網時長、時段、網購金額),其中分枝“上網時長>1.1h” 很顯然已經過擬合了,這個數據集上A,B也許恰好A每天上網1.09h, B上網1.05小時,但用上網時間是不是>1.1小時來判斷所有人的年齡很顯然是有悖常識的;
相對來說圖2的boosting雖然用了兩棵樹 ,但其實只用了2個feature就搞定了,后一個feature是問答比例,顯然圖2的依據更靠譜。(當然,這里是LZ故意做的數據,所以才能靠譜得如此狗血。實際中靠譜不靠譜總是相對的) Boosting的最大好處在於,每一步的殘差計算其實變相地增大了分錯instance的權重,而已經分對的instance則都趨向於0。這樣后面的樹就能越來越專注那些前面被分錯的instance。就像我們做互聯網,總是先解決60%用戶的需求湊合着,再解決35%用戶的需求,最后才關注那5%人的需求,這樣就能逐漸把產品做好,因為不同類型用戶需求可能完全不同,需要分別獨立分析。如果反過來做,或者剛上來就一定要做到盡善盡美,往往最終會竹籃打水一場空。
四、Shrinkage
Shrinkage(縮減)的思想認為,每次走一小步逐漸逼近結果的效果,要比每次邁一大步很快逼近結果的方式更容易避免過擬合。即它不完全信任每一個棵殘差樹,它認為每棵樹只學到了真理的一小部分,累加的時候只累加一小部分,通過多學幾棵樹彌補不足。用方程來看更清晰,即
沒用Shrinkage時:(yi表示第i棵樹上y的預測值, y(1~i)表示前i棵樹y的綜合預測值)
y(i+1) = 殘差(y1~yi), 其中: 殘差(y1~yi) = y真實值 - y(1 ~ i)
y(1 ~ i) = SUM(y1, ..., yi)
Shrinkage不改變第一個方程,只把第二個方程改為:
y(1 ~ i) = y(1 ~ i-1) + step * yi
即Shrinkage仍然以殘差作為學習目標,但對於殘差學習出來的結果,只累加一小部分(step殘差)逐步逼近目標,step一般都比較小,如0.01~0.001(注意該step非gradient的step),導致各個樹的殘差是漸變的而不是陡變的。直覺上這也很好理解,不像直接用殘差一步修復誤差,而是只修復一點點,其實就是把大步切成了很多小步。本質上,Shrinkage為每棵樹設置了一個weight,累加時要乘以這個weight,但和Gradient並沒有關系*。 這個weight就是step。就像Adaboost一樣,Shrinkage能減少過擬合發生也是經驗證明的,目前還沒有看到從理論的證明。
GBDT的適用范圍
該版本GBDT幾乎可用於所有回歸問題(線性/非線性),相對logistic regression僅能用於線性回歸,GBDT的適用面非常廣。亦可用於二分類問題(設定閾值,大於閾值為正例,反之為負例)。
五、XGboost/GBDT調參
推薦GBDT樹的深度:6;(橫向比較:DecisionTree/RandomForest需要把樹的深度調到15或更高)以下摘自知乎上的一個問答(詳見參考文獻8),問題和回復都很好的闡述了這個參數設置的數學原理。
【問】xgboost/gbdt在調參時為什么樹的深度很少就能達到很高的精度?
用xgboost/gbdt在在調參的時候把樹的最大深度調成6就有很高的精度了。但是用DecisionTree/RandomForest的時候需要把樹的深度調到15或更高。用RandomForest所需要的樹的深度和DecisionTree一樣我能理解,因為它是用bagging的方法把DecisionTree組合在一起,相當於做了多次DecisionTree一樣。但是xgboost/gbdt僅僅用梯度上升法就能用6個節點的深度達到很高的預測精度,使我驚訝到懷疑它是黑科技了。請問下xgboost/gbdt是怎么做到的?它的節點和一般的DecisionTree不同嗎?
【答】
這是一個非常好的問題,題主對各算法的學習非常細致透徹,問的問題也關系到這兩個算法的本質。這個問題其實並不是一個很簡單的問題,我嘗試用我淺薄的機器學習知識對這個問題進行回答。
一句話的解釋,來自周志華老師的機器學習教科書( 機器學習-周志華):Boosting主要關注降低偏差,因此Boosting能基於泛化性能相當弱的學習器構建出很強的集成;Bagging主要關注降低方差,因此它在不剪枝的決策樹、神經網絡等學習器上效用更為明顯。
隨機森林(random forest)和GBDT都是屬於集成學習(ensemble learning)的范疇。集成學習下有兩個重要的策略Bagging和Boosting。
Bagging算法是這樣做的:每個分類器都隨機從原樣本中做有放回的采樣,然后分別在這些采樣后的樣本上訓練分類器,然后再把這些分類器組合起來。簡單的多數投票一般就可以。其代表算法是隨機森林。Boosting的意思是這樣,他通過迭代地訓練一系列的分類器,每個分類器采用的樣本分布都和上一輪的學習結果有關。其代表算法是AdaBoost, GBDT。
其實就機器學習算法來說,其泛化誤差可以分解為兩部分,偏差(bias)和方差(variance)。這個可由下圖的式子導出(這里用到了概率論公式D(X)=E(X2)-[E(X)]2)。偏差指的是算法的期望預測與真實預測之間的偏差程度,反應了模型本身的擬合能力;方差度量了同等大小的訓練集的變動導致學習性能的變化,刻畫了數據擾動所導致的影響。這個有點兒繞,不過你一定知道過擬合。
如下圖所示,當模型越復雜時,擬合的程度就越高,模型的訓練偏差就越小。但此時如果換一組數據可能模型的變化就會很大,即模型的方差很大。所以模型過於復雜的時候會導致過擬合。
當模型越簡單時,即使我們再換一組數據,最后得出的學習器和之前的學習器的差別就不那么大,模型的方差很小。還是因為模型簡單,所以偏差會很大。

也就是說,當我們訓練一個模型時,偏差和方差都得照顧到,漏掉一個都不行。
對於Bagging算法來說,由於我們會並行地訓練很多不同的分類器的目的就是降低這個方差(variance) ,因為采用了相互獨立的基分類器多了以后,h的值自然就會靠近.所以對於每個基分類器來說,目標就是如何降低這個偏差(bias),所以我們會采用深度很深甚至不剪枝的決策樹。
對於Boosting來說,每一步我們都會在上一輪的基礎上更加擬合原數據,所以可以保證偏差(bias),所以對於每個基分類器來說,問題就在於如何選擇variance更小的分類器,即更簡單的分類器,所以我們選擇了深度很淺的決策樹。
六、其他
Gradient Boosting算法:xgboost,在計算速度和准確率上,較GBDT有明顯的提升。xgboost 的全稱是eXtreme Gradient Boosting,它是Gradient Boosting Machine的一個c++實現,作者為正在華盛頓大學研究機器學習的大牛陳天奇 。xgboost最大的特點在於,它能夠自動利用CPU的多線程進行並行,同時在算法上加以改進提高了精度。它的處女秀是Kaggle的 希格斯子信號識別競賽,因為出眾的效率與較高的預測准確度在比賽論壇中引起了參賽選手的廣泛關注。值得我們在GBDT的基礎上對其進一步探索學習。
參考: