前向分步演算法 && AdaBoost演算法 && 提升樹(GBDT)演算法 && XGBoost演算法

Andrew.Hann發表於2017-09-18

1. 提升方法

提升(boosting)方法是一種常用的統計學方法,在分類問題中,它通過逐輪不斷改變訓練樣本的權重,學習多個分類器,並將這些分類器進行線性組合,提高分類的效能

0x1: 提升方法的基本思路

提升方法基於這樣一種思想:對於一個複雜任務來說,將多個專家的判斷進行適當(按照一定權重)綜合(例如線性組合加法模型)所得出的判斷,要比其中任何一個專家單獨的判斷好

歷史上,Kearns和Valiant首先提出了“強可學習(strongly learnable)”和“弱可學習(weekly learnable)”的概念,指出在概率近似正確(probably approximately correct,PAC)學習的框架中

1. 一個概念(概率規律)如果存在一個多項式的學習演算法能夠學習它(通過建模抽象擬合),並且正確率很高,那麼就稱這個概念是強可學習的;
2. 一個概念如果存在一個多項式的學習演算法能夠學習它,但是學習的正確率僅比隨機猜測略好,那麼就稱這個概念是弱可學習的

同時,後來Schapire證明強在PAC學習的框架下,一個概念是強可學習的充分必要條件是這個概念是弱可學習的。這樣一來,問題就轉化為了,在演算法訓練建模中,如果已經發現了“弱可學習演算法”(即當前分類效果並不優秀,甚至僅僅比隨機預測效果要好),就有可能將其boosting(提升)為強可學習演算法,這其中最具代表性的方法就是AdaBoosting(AdaBoosting algorithm)

提升方法就是從弱學習演算法出發,反覆學習,得到一系列弱分類器(基本分類器),然後組合這些弱分類器,構成一個強分類器。大多數的提升方法都是改變訓練資料的概率分佈(訓練資料的權重分佈)

0x2:提升方法的兩個關鍵要素

對於提升方法來說,有兩個非常重要的問題

1. 在每一輪如何改變訓練資料的權值或概率分佈,修改的策略是什麼?
2. 如何將弱分類器組合成一個強分類器?

這2個問題是所有Boosting方法都要考慮和解決的問題,這裡以AdaBoost為例,討論AdaBoost的策略

1. 提高那些被前一輪弱分類器錯誤分類的樣本的權值,而降低那些被正確分類樣本的權值。這樣一來,那些被分錯的資料,在下一輪就會得到更大的關注。所以,分類問題被一系列的弱分類器“分而治之”
2. 對弱分類器的組合,AdaBoost採取加權多數表決的方法。即加大分類誤差率小的弱分類器的權值,使其在表決中起較大作用,減小分類誤差率大的弱分類器的權值,使其在表決中起較小的作用

Relevant Link:

https://cseweb.ucsd.edu/~yfreund/papers/IntroToBoosting.pdf
http://blog.csdn.net/dark_scope/article/details/14103983

 

2. 前向分步演算法

在開始學習AdaBoost演算法之前,我們需要先了解前向分步演算法思想。實際上,AdaBoost演算法是模型為加法模型、損失函式為指數函式、學習演算法為前向分步演算法時的二類分類學習演算法

0x1:加法模型(aditive model)

加法模型是一種線性模型,,其中,為基函式,為基函式的引數,為基函式的係數(權重)

在給定訓練資料及損失函式的條件下,學習加法模型成為經驗風險極小化(即損失函式極小化)問題:

即同時考慮N個樣本在整個線性模型組中的損失函式的極小值,通常這是一個十分複雜的優化問題(求極值問題),想要一步到位求出最優解特別困難。前向分步演算法(forward stagewise algorithm)求解這一優化問題的思想是:

因為學習的是加法模型(線性模型),如果能夠從前向後,每一步只學習一個基函式及其係數,逐步逼近優化目標函式式,那麼就可以極大簡化優化的複雜度

具體地,每步只需要優化如下損失函式:,即一次只要考慮一個基函式及其係數即可

有一點要注意,前向分步的思想和貝葉斯估計有類似的地方:

它們都假設每一步之間的基函式和係數是獨立不相關的(在貝葉斯估計中這叫獨立同分布),也因為這一假設才可以把原始的全域性最優解求解等價為分步的子項求解過程。
但是這種假設會丟失一部分精確度,即每一步之間的依賴關聯會被丟棄

而前向分步演算法的思想就是不求一步到位,而是逐步逼近最優解,通過分步求得每一步的最優解來逼近全域性最優解。我個人覺得這和SGD梯度下降的求最優思想是一樣的

0x2:演算法策略

和其他統計機器學習模型一樣,前向分佈演算法的策略也同樣是:經驗風險最小化。如果在模型中加入了penalty懲罰項,則可以演進為結構風險最小化

0x3: 前向分步演算法

給定訓練資料集,損失函式和基函式的集合,學習加法模型的前向分步演算法如下

(1)初始化

(2)對m = 1,2,3...,M(M代表基函式個數)

  (a)在上一步得到的最優基函式的基礎上,極小化本次單個基函式的損失函式:,得到本輪最優基函式引數

  (b)更新(線性累加基函式)

(3)得到最終加法模型

這樣,前向分步演算法將同時求解從m=1到M所有引數的全域性最優解問題簡化為逐次求解各個的區域性最優化問題

Relevant Link:

https://en.wikipedia.org/wiki/Additive_model
https://en.wikipedia.org/wiki/Generalized_additive_model
http://www.stat.cmu.edu/~ryantibs/advmethods/notes/addmodels.pdf

 

3. AdaBoost演算法

0x1:演算法過程

假設給定一個二類分類的訓練資料集(adaboost不限於二類分類),其中,每個樣本點由例項與標記組成。例項是例項空間,是標記集合。AdaBoost利用以下演算法,從訓練資料集中學習一系列弱分類器或基本分類器,並將這些弱分類器線性組合成一個強分類器

  • (1)初始化訓練資料的權值分佈(N代表樣本數量):(初始等概率分佈體現了最大熵原理,在沒有任何先驗知識的前提下作等概率假設是最合理的)。這一步假設資料集具有均勻的權值分佈,即每個訓練樣本在基本分類器的學習中作用相同,這一假設保證第一步能夠在原始資料上學習基本分類器
  • (2)假設訓練輪次為M(直到達到某個預定的足夠小的錯誤率或達到預先指定的最大迭代次數),則對m = 1,2,....,M

  (2.1)使用具有權值分佈的訓練資料集(對應本輪權值分佈的資料集)學習,得到本輪次的基本分類器:

  (2.2)計算在本輪訓練資料集上的分類誤差率(權重誤差函式):在加權的訓練資料集上的分類誤差率是被誤分類樣本的權值之和,注意,權重誤差函式關注的是本輪資料集的權重(概率)分佈,而不關注弱分類器內部的引數。即我們對本輪高概率分佈(重點關注的資料)的錯誤會給與更大的懲罰,這樣就體現了模型Adding組合過程中根據權重誤差進行模型組合選擇的策略了

  (2.3)根據本輪的弱分類器對資料集的分類誤差計算的模型係數:,代表了本輪得到的弱分類器的重要程度。由左式可知,當時,,並且隨著的減小而增大,所以在本輪分類誤差率越小的基本分類器在最終分類器中的作用越大

  (2.4)更新下一輪訓練資料集的權值分佈:是規範化因子:,它使得成為一個概率分佈(每一輪的權值總和都為1,)。由此可知,被基本分類器誤分類樣本的權值得以擴大,而被正確分類樣本的權值卻在下一輪得以縮小。兩相比較,誤分類樣本的權值被放大了倍,因此誤分類樣本在下一輪學習中起更大作用。不改變所給的訓練資料本身,而不斷改變訓練資料權值的分佈,使得訓練資料在基本分類器的學習中起不同的作用,一次優化一個弱分類模型,或者理解理解為一次優化全域性複雜問題中的一次子問題(分而治之)

從數學的角度看,這也是一個平滑單調遞增函式和 log 指數函式組合得到的動態增減平衡得到的神奇效果

  • (3)構建基本分類器的線性組合:,得到最終分類器:。線性組合實現M個基本分類器的加權表決。係數表示了基本分類器的重要性
可以看到,在每輪的訓練中,訓練樣本的權值分佈不斷在變動,同時
1. 權值分佈對本輪的弱分類器在最終線性分類器組合中重要程度起正比例作用;
2. 對下一輪的樣本權值調整起反比例作用

0x2:演算法策略

毫無疑問是經驗風險最小化策略

0x3:AdaBoost的一個例子

分析一下書上給的例子的計算過程,體會adaboost的思想

初始化訓練資料的權值分佈:,在第一輪輸入原始資料本身

1. 迭代過程 m = 1

要確定本輪的權重誤差率,首先要"確定"出本輪的模型內部引數(但是最終誤差損失的評估同時也受本輪資料集的權重分佈影響,所以同一份資料每一輪的模型最優引數解都不一樣),題目所給的模型是一個離散而分類模型,離散代表著模型的最優解是有一個區間的,最優解並不唯一(例如v取1.5和v取1.2都是等價的)。我們遍歷【-0.5,0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5】比較模型誤差率最小的模型內部引數,經過計算可得,對於m=1,在權值分佈為D1(10個資料,每個資料的權值皆初始化為0.1)的訓練資料上

  1. 閾值v取2.5時誤差率為0.3(x < 2.5時取1,x > 2.5時取-1,則6 7 8分錯,誤差率為0.3),
  2. 閾值v取5.5時誤差率最低為0.4(x < 5.5時取1,x > 5.5時取-1,則3 4 5 6 7 8皆分錯,誤差率0.6大於0.5,不可取。故令x > 5.5時取1,x < 5.5時取-1,則0 1 2 9分錯,誤差率為0.4),
  3. 閾值v取8.5時誤差率為0.3(x < 8.5時取1,x > 8.5時取-1,則3 4 5分錯,誤差率為0.3)。
  4. ...其他類推可自己計算

可以看到,無論閾值v取2.5,還是8.5,總得分錯3個樣本,故可任取其中任意一個如2.5,弄成第一個基本分類器為:

從而得到G1(x)在訓練資料集上的誤差率(被G1(x)誤分類樣本“6 7 8”的權值之和)e1=P(G1(xi)≠yi) = 3*0.1 = 0.3

然後根據誤差率e1計算G1的係數:

接著更新訓練資料的權值分佈,用於下一輪迭代:

第一輪迭代後,最後得到各個資料的權值分佈D2 = (0.0715, 0.0715, 0.0715, 0.0715, 0.0715,  0.0715, 0.1666, 0.1666, 0.1666, 0.0715)。由此可以看出

1. 因為樣本中是資料“6 7 8”被G1(x)分錯了,所以它們的權值由之前的0.1增大到0.1666
2. 反之,其它資料皆被分正確,所以它們的權值皆由之前的0.1減小到0.0715

分類函式f1(x)= a1*G1(x) = 0.4236G1(x)

從上述第一輪的整個迭代過程可以看出:被誤分類樣本的權值之和影響誤差率,誤差率影響基本分類器在最終分類器中所佔的權重,每輪被誤分類的樣本的調整幅度是一致的。

2. 迭代過程 m = 2

對於m=2,在權值分佈為D2 = (0.0715, 0.0715, 0.0715, 0.0715, 0.0715,  0.0715, 0.1666, 0.1666, 0.1666, 0.0715)的訓練資料上,經過計算可得:

  1. 閾值v取2.5時誤差率為0.1666*3(x < 2.5時取1,x > 2.5時取-1,則6 7 8分錯,誤差率為0.1666*3),
  2. 閾值v取5.5時誤差率最低為0.0715*4(x > 5.5時取1,x < 5.5時取-1,則0 1 2 9分錯,誤差率為0.0715*3 + 0.0715),
  3. 閾值v取8.5時誤差率為0.0715*3(x < 8.5時取1,x > 8.5時取-1,則3 4 5分錯,誤差率為0.0715*3)

所以,閾值v取8.5時誤差率最低,故第二個基本分類器為:

G2(x)把樣本“3 4 5”分錯了,根據D2可知它們的權值為0.0715, 0.0715,  0.0715,所以G2(x)在訓練資料集上的誤差率e2=P(G2(xi)≠yi) = 0.0715 * 3 = 0.2143。

計算G2的係數:

更新訓練資料的權值分佈:

D3 = (0.0455, 0.0455, 0.0455, 0.1667, 0.1667,  0.01667, 0.1060, 0.1060, 0.1060, 0.0455)。被分錯的樣本“3 4 5”的權值變大,其它被分對的樣本的權值變小

f2(x)=0.4236G1(x) + 0.6496G2(x)

3. 迭代過程 m = 3

對於m=3,在權值分佈為D3 = (0.0455, 0.0455, 0.0455, 0.1667, 0.1667,  0.01667, 0.1060, 0.1060, 0.1060, 0.0455)的訓練資料上,經過計算可得:

  1. 閾值v取2.5時誤差率為0.1060*3(x < 2.5時取1,x > 2.5時取-1,則6 7 8分錯,誤差率為0.1060*3),
  2. 閾值v取5.5時誤差率最低為0.0455*4(x > 5.5時取1,x < 5.5時取-1,則0 1 2 9分錯,誤差率為0.0455*3 + 0.0715),
  3. 閾值v取8.5時誤差率為0.1667*3(x < 8.5時取1,x > 8.5時取-1,則3 4 5分錯,誤差率為0.1667*3)

所以閾值v取5.5時誤差率最低,故第三個基本分類器為:

此時,被誤分類的樣本是:0 1 2 9,這4個樣本所對應的權值皆為0.0455,所以G3(x)在訓練資料集上的權重誤差率e3 = P(G3(xi)≠yi) = 0.0455*4 = 0.1820

計算G3的係數:

更新訓練資料的權值分佈:D4 = (0.125, 0.125, 0.125, 0.102, 0.102,  0.102, 0.065, 0.065, 0.065, 0.125)。被分錯的樣本“0 1 2 9”的權值變大,其它被分對的樣本的權值變小

f3(x)=0.4236G1(x) + 0.6496G2(x)+0.7514G3(x)

此時,得到的第三個基本分類器sign(f3(x))在訓練資料集上有0個誤分類點。至此,整個訓練過程結束

從上述過程中可以發現:如果某些個樣本被分錯,它們在下一輪迭代中的權值將被增大(讓模型傾向於在下一輪把這些樣本點分對),同時,其它被分對的樣本在下一輪迭代中的權值將被減小。就這樣,分錯樣本權值增大,分對樣本權值變小,而在下一輪迭代中,總是選取讓誤差率最低的閾值來設計基本分類器,所以每輪的誤差率e(所有被Gm(x)誤分類樣本的權值之和)不斷降低。看起來就是最終線性模型組合的總體誤差率在每一輪的訓練中不斷降低

綜上,將上面計算得到的a1、a2、a3各值代入G(x)中,G(x) = sign[f3(x)] = sign[ a1 * G1(x) + a2 * G2(x) + a3 * G3(x) ],得到最終的分類器為:

G(x) = sign[f3(x)] = sign[ 0.4236G1(x) + 0.6496G2(x)+0.7514G3(x) ]

可以看到,每一輪迭代中閾值的選擇是通過一個類似learning rate的學習率,可以理解為步長,去限制弱學習器的迭代次數

(scikitlearn的AdaBoostClassifier 中的learning_rate引數)

書中例子只有一個變數x,因此梯度為1可以忽略,可看成在原資料上學習率(步長)為0.5,去進行弱分類器的迭代,一次單變數的梯度下learning rate看起來和for迴圈遍歷形式上是一樣的

....
n_step = 0.5
features_min = min(features)
features_max = max(features)
# 步長
n_step = (features_max - features_min + self.learning_rate) // self.learning_rate

for i in range(1, int(n_step)):
        v = features_min + self.learning_rate * i
        # 加入條件:閾值與資料點不重合   
        if v not in features:
            # 誤分類計算
            ....

0x4: 前向分佈演算法與AdaBoost的關係

在前面的章節中,我們討論了加法模型(aditive model)與它的一個最優解近似求解演算法前向分步演算法。其實本質上說,AdaBoost還有另外一種解釋,即可以認為:

AdaBoost是模型為加法模型、損失函式為指數函式、學習演算法為前向分步演算法的二類分類學習方法,AdaBoost演算法就是前向分步演算法的一個特例

AdaBoost中,各個基本分類器就相當於加法模型中的基函式,且其損失函式為指數函式

換句話說,當前向分步演算法中的基函式為Adaboost中的基本分類器時,加法模型等價於Adaboost的最終分類器

Relevant Link:

http://blog.csdn.net/v_july_v/article/details/40718799
http://blog.csdn.net/dark_scope/article/details/14103983 
https://www.zhihu.com/question/65357931
http://blog.csdn.net/v_july_v/article/details/40718799 

 

4. 提升樹(GBDT Gradient Boostring Decision Tree)

提升樹是一種以分類樹或迴歸樹為基本分類器的提升方法

0x1: 提升樹模型

提升樹實際採用加法模型(基函式的線性組合)與前向分步演算法。以決策樹為基函式的提升方法稱為提升樹(boosting tree),對二分類問題決策樹是二叉樹,對迴歸問題決策樹是二叉迴歸樹。提升樹模型可以表示為決策樹的加法模型,其中表示決策樹;表示決策樹內部引數(選哪個特徵作為切分點;閾值多少);M 為整個模型的個數

0x2: 提升樹演算法

提升樹演算法採用前向分步演算法,首先確定初始提升樹,第m步的模型是:,其中為上一輪訓練得到的單個基本分類器,通過經驗風險極小化確定下一棵決策樹的引數

如果抽象來看,把每個基分類器的權重概率看作模型的引數,即每一輪的模型都接收上一步模型的引數作為輸入,這一點很像深度神經網路的層一層之間的關係。
區別在於Boosting方法每輪得到的模型引數在輸入下一輪迭代時是固定不變的,在每輪跌倒之間變動的只有:1)資料的概率權重;及2)模型的決策權重,而DNN會在每輪迭代中不斷調整模型自身內部的所有神經元(對應基分類器)的內部引數。
打個不巧當的比喻:DNN堅信自己就是最棒的,不斷提升自己。而Boostring認為眾人拾柴火焰高,一個人不行我們就用祖父子->祖父子代代之間不斷去優化,然後大家一起來參與決策

由於樹的線性組合可以很好地擬合訓練資料中存在的概率規則分佈(可能是多峰的),即使資料中的輸入與輸出之間的關係很複雜也是如此,所以提升樹是一個高效地學習演算法。

下面討論針對不同問題的提升樹學習演算法,其主要區別在於使用的損失函式不同:

1)用平方誤差損失函式的迴歸問題:用平方誤差求導更平滑可微;

2)用指數損失函式的分類問題;

3)用一般損失函式的一般決策問題;

1. 二分類問題提升樹

對於二分類問題,提升樹演算法只需要將AdaBoost演算法中的基本分類器(階躍分類器)限制為二類分類樹即可,可以說這時的提升樹演算法是AdaBoost演算法的特殊情況

這裡插一句:前面例子中看到的基本分類器 x < v 或 x > v,可以看作是由一個根節點直接連線的兩個葉節點的簡單決策樹,即所謂的決策樹樁(decision stump)

2. 迴歸問題的提升樹

已知一個訓練資料集為輸入空間,為輸出空間。如果將輸入空間劃分為 J 個互不相交的區域 R1,R2,...,Rj,並且在每個區域上確定輸出的常量Cj(連續區間的離散取樣值),那麼樹可以表示為:,其中,引數 表示樹的區域劃分和各區域上的常數。J 是迴歸樹的複雜度即葉節點個數(取樣粒度)

迴歸問題提升樹使用以下前向分步演算法:

在前向分步演算法的第 m 步,給定當前模型 (上一輪訓練得到的模型),需求解,得到,即第 m 棵樹的引數

當採用平方誤差損失函式時,,其損失變為:

這裡,是當前模型擬合訓練資料的殘差(residual),所以,對迴歸問題的提升樹演算法來說,只需簡單地擬合當前模型的殘差即可。演算法流程如下

(1) 初始化

(2)對 m = 1,2,...,M,M代表該加法模型總共有M個基本模型進行線性組合,在每一輪的訓練中都進行如下步驟

  (a)計算殘差

  (b)擬合殘差(殘差最小化)學習一個迴歸樹,得到

  (c)更新

(3)得到迴歸問題提升樹:

0x3: 提升樹演算法的一個例子

來一步步推導下書上的例子加深理解和印象

1. 第一次迭代 m = 1

對第一次迭代來說,提升樹輸入的是原始資料,殘差等於原始樣本輸入

即迴歸樹。首先通過以下優化問題:求解訓練資料的切分點s:

容易求得在R1,R2內部使平方誤差達到最小的C1,C2為:(離散取樣點取子集的均值可以使得平方誤差最小),這裡N1,N2是R1,R2的樣本個數

每一輪迭代訓練中要計算的就是訓練資料的切分點,這裡可以採取遍歷所有可能值的策略求得最優切分點s,s及m(s)的計算結果如下

可知當s = 6.5時m(s)達到最小值,此時,所有迴歸樹為:

擬合訓練資料的殘差用於輸入下一輪迭代訓練(從第二輪開始模型的輸入就是殘差了,這是GBDT區別於普通迴歸決策樹的一個區別)如下表所示

擬合訓練資料的平方損失誤差:

仔細看這個結果,我們會發現:從第二輪開始,輸入下一輪的就不再是原始資料,而是資料的“離心距離”,即距離最佳分類面的距離。

2. 第二次迭代 m = 2

提升樹和AdaBoost的核心思想是一樣的,即:分而治之,每一輪迭代的“誤報量”會被傳遞到下一輪,在下一輪的迭代中通過調整基本函式內部引數對那部分“誤報量“進行重點解決

在AdaBoost中,上一輪誤報的樣本點會在下一輪按照一定的比例被提高權重,而在提升樹中。這種思想通過殘差得以體現,上一輪分類錯誤的殘差被作為樣本點傳入進行模型訓練,這一輪的目的就是盡力消弭這部分殘差

這一輪的訓練樣本是上一輪的殘差

通過遍歷所有可能分界點s,可以得到:,-0.52、0.22分別是左右分類子集的均值(滿足平方誤差最小)

至此,兩個不等式線性相加的結果

注意到這裡和普通迴歸決策樹的不同:GBDT每一輪得到的基分類器線性組合都同時包括此前的基分類器結果以及本輪的訓練擬合結果,而普通迴歸決策樹每輪迭代得到的區間基分類器都僅僅取決於原是樣本

擬合原始訓練資料的平方損失誤差是:(比第一輪的損失函式在下降)

# -*- coding:utf-8 -*-

import math

def f2_fuc(x):
    if x < 3.5:
        return 5.72
    elif x < 6.5:
        return 6.46
    else:
        return 9.13

if __name__ == "__main__":
    loss = 0
    train_data = {
        1: 5.56,
        2: 5.7,
        3: 5.91,
        4: 6.4,
        5: 6.8,
        6: 7.05,
        7: 8.9,
        8: 8.7,
        9: 9.0,
        10: 9.05
    }
    for i in train_data:
        loss += (train_data[i] - f2_fuc(i)) ** 2

    print loss

3. 繼續往下迭代

擬合原始訓練資料的平方損失誤差是:

假設此時已經滿足停止條件,則即為所求提升樹(它的區間離散取樣值是由多課決策樹線性組合而成決定的)

0x4: 更加general泛化的殘差求解方式 - 梯度提升

提升樹利用加法模型與前向分步演算法實現學習的優化過程。當損失函式是平方損失和指數損失函式時,每一步優化是相對簡單的(我們都可以通過求導得到最佳離散化取樣值c1/c2),但對一般泛化的損失函式而言,往往每一步的優化並不容易(針對連續迴歸函式的複雜函式的擬合場景)。針對這一問題,Freidman提出了梯度提升(gradient boosting)演算法,梯度提升的關鍵是利用損失函式的負梯度(負導數) 作為迴歸問題提升樹演算法中的殘差的近似值(負梯度同樣體現了該區間內樣本資料和最佳分介面的“離心程度”),擬合一個迴歸樹

(1)初始化:

(2)對 m = 1,2,...,M,M代表該加法模型總共有M個基本模型進行線性組合,在每一輪的訓練中都進行如下步驟

  (a)對 i = 1,2,...,N(N個樣本),計算:(計算損失函式的負梯度在當前模型的值,將它作為殘差的估計,對於平方損失函式它就是殘差;對於一般的損失函式,它就是殘差的近似值)

  (b)對擬合一個迴歸樹,得到第 m 棵樹的葉節點區域,j = 1,2,...,J(葉節點不一定等於2)

  (c)對 j = 1,2,...,J,計算(利用線性搜尋估計葉節點區域的值,尋找使得誤差梯度最小的離散取樣值c)

  (d)更新 (每個基本函式由該棵樹的所有葉節點的離散取樣值組成)

(3)得到迴歸樹:

Relevant Link:

https://www.zhihu.com/question/60625492/answer/200165954
http://www.jianshu.com/p/005a4e6ac775

 

5. xgboost(Scalable and Flexible Gradient Boosting)

0x1:用一個圖例說明XGboost模型

我們用一個簡單的例子來引入對Xgboost的討論,我們的目標是根據一些屬性特性,判斷一個家庭裡的成員是否喜歡玩電腦遊戲

1. 單個CART樹的預測

可以看到,CART樹和decision tree有一些不同,CART樹的葉節點對應的是一個分值,而不像分類決策樹是一個確定的類別,CART樹的這個分值我們可以理解為權重

2. 兩個CART樹的線性加和組合

簡單來說,xgboost對應的模型就是一堆CART樹的線性組合,和GBDT一樣,XGBoost將每棵樹的預測值加到一起作為最終的預測值

第二圖的底部說明了如何用一堆CART樹做預測,就是基於“addive model加法線性模型”的思想,將各個樹的預測分數相加 。通過這種多基分類器加和(類似DNND中的多神經元)綜合判斷的方式,各個基模型互相補充,實現對多峰概率分佈的擬合。這也體現了ensemble learning整合學習的思想

0x2:XGBoost數學模型

我們用數學來準確地表示這個模型:

這裡的K就是樹的棵數,F表示所有可能的CART樹,f表示一棵具體的CART樹。這個模型由K棵CART樹組成。

模型的目標函式如下:

這個目標函式同樣包含兩部分

1. 第一部分就是損失函式:MSE或指數損失(例如交叉熵損失)
2. 第二部分就是正則項,這裡的正則化項由K棵樹的正則化項相加而來,體現了整體模型的複雜度

我們希望XGBoost得到的是一個: simple and predictive model

0x3:XGBoost模型訓練策略 - 前向分步策略(逐輪加法訓練)

幾乎對於所有的有監督機器學習模型來說,訓練過程就是找到一個目標函式,然後優化求導求極值。

但是XGBoost的模型:是由K棵樹以及每棵樹中的所有葉節點值組成的加法模型,要對其進行全域性求導;或者是進行梯度下降都是很困難的,或者說在計算上非常複雜。

解決這個問題,我們可以使用“加法訓練”,即我們一次只訓練一棵樹,同時把上一輪得到的所有ensemble tree結果作為本輪的輸入:

在第t步時,我們新增了一棵最優的CART樹ft,這棵最優的CART樹ft是怎麼得來的呢?就是在現有的t-1棵樹的基礎上,使得目標函式最小的那棵CART樹,如下圖所示:

假如我們使用的損失函式時MSE,那麼上述表示式會變成這個樣子:

這個式子非常漂亮,因為它含有ft(xi)的一次式和二次式,而且一次式項的係數是殘差。注意:這裡模型的引數 ft(xi) 就是CART樹葉子結點的值

但是對於其他的損失函式(指數損失和一般損失),我們未必能得出如此漂亮的式子,所以,對於一般的損失函式,我們需要將其作泰勒二階展開,如下所示: 

其中:

在這個公式中,constant代表的 t -1 棵樹的正則化項;l(yi, yi^t-1)也是常數項;剩下的三個變數項分別是第t棵CART樹的一次式,二次式;和整棵樹的正則化項。

我們的目標在在這輪迭代中,讓目標函式最小化,所以可以把常數項去掉,公式整理後如下:

obj*代表了什麼呢?它表示了這棵樹的結構有多好,值越小,代表這樣結構越好!也就是說,它是衡量第t棵CART樹的結構好壞的標準。這個值僅僅是用來衡量結構的好壞的,與葉子節點的值可是無關的。如下圖所示:

有了評判樹的結構好壞的標準,我們就可以先求最佳的樹結構,這個定出來後,最佳的葉子結點的值實際上在上面已經求出來了(模型的引數也就得到了)。

問題是:樹的結構近乎無限多,一個一個去測算它們的好壞程度,然後再取最好的顯然是不現實的。所以,我們仍然需要採取“逐輪迭代漸進逼近全域性最優策略”,我們每次只優化一層的樹結點,得到在這層裡最優的樹結構,即找到一個最優的切分點,使得切分後的Gain最大(和決策樹的基尼指數求解最優分介面的思想是一致的)。
掃描結束後,我們就可以確定是否切分,如果切分,對切分出來的兩個節點,遞迴地呼叫這個切分過程,我們就能獲得一個相對較好的樹結構。

我們以上文提到過的判斷一個人是否喜歡計算機遊戲為例子。最簡單的樹結構就是一個節點的樹。我們可以算出這棵單節點的樹的好壞程度obj*。假設我們現在想按照年齡將這棵單節點樹進行分叉,我們需要知道:

1、按照年齡分是否有效,也就是是否減少了obj的值
2、如果可分,那麼以哪個年齡值來分。

為了回答上面兩個問題,我們可以將這一家五口人按照年齡做個排序。如下圖所示:

這個Gain實際上就是單節點的obj*減去切分後的兩個節點的樹obj*,Gain如果是正的,並且值越大,表示切分後obj*越小於單節點的obj*,就越值得切分。

同時,我們還可以觀察到,Gain的左半部分如果小於右側的,則Gain就是負的,表明切分後obj反而變大了。

在這裡實際上是一個臨界值,它的值越大,表示我們對切分後obj下降幅度要求越嚴。這個值也是可以在xgboost中設定的。這個實際在本質上就起到了剪枝限制的作用,這也是XGboost和決策樹的一個不同點:普通的決策樹在切分的時候並不考慮樹的複雜度,而依賴後續的剪枝操作來控制。xgboost在切分的時候就已經考慮了樹的複雜度,就是那個引數。所以,它不需要進行單獨的剪枝操作

0x4:XGboost的優點

從這個目標函式可以看出XGBoost的優點之處:

1. 目標函式中的一次式,二次式的係數是 gi 和 hi,而 gi 和 hi 是彼此獨立的,可以並行的計算,這帶來了計算速度上的併發優勢
2. 而且,gi 和 hi是不依賴於損失函式的形式,只要這個損失函式是二次可微即可,所以 XGBoost可以自定義損失函式
Relevant Link:

https://www.jianshu.com/p/7467e616f227 
https://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf
https://xgboost.readthedocs.io/en/latest/model.html
https://www.cnblogs.com/csyuan/p/6537255.html 
http://blog.csdn.net/a819825294/article/details/51206410
http://blog.csdn.net/sb19931201/article/details/52557382
http://blog.csdn.net/github_38414650/article/details/76061893

Copyright (c) 2018 LittleHann All rights reserved

相關文章