梯度提升決策樹(Gradient Boosting Decision Tree,GBDT)
集成學習的系列博客:
今天來講一講GBDT,GBDT的名聲如雷貫耳,早在深度學習沒火之前,集成學習大行其道的時候,GBDT無論是在機器學習比賽中,還是在工業界(尤其CTR預估)都被廣泛使用,因爲其優秀的性能。GBDT的改進如陳天奇的XGBoost和微軟的LightGBM不僅性能優秀,尤其計算速度相比較原始的GBDT有巨大的提升,這兩個算法都有現成的python庫提供,當我們使用的時候可以調用,sklearn中也封裝了基本的GBDT模型,想用也可以直接調用。
這篇博客想粗淺的講下GBDT,只講迴歸,雖然GBDT也可以用於分類,但貌似工業界迴歸用的多一些。首先GBDT是boosting算法中的一種,因此學習GBDT需要的前驗知識有:
- Boosting這一類算法思想
- 分類與迴歸樹(CART)迴歸部分
- 提升樹
1、關於Boosting這一類算法思想倒也簡單,因爲博客集成學習(ensemble learning)基礎知識已經講得很清楚了,這裏不再累述,不清楚的請移步這篇博客。
2、分類與迴歸樹(CART)迴歸部分,我的博客分類與迴歸樹(classification and regression tree,CART)之迴歸也有詳細的講解,因此,這裏也不太講解,不清楚的請移步。因爲GBDT中的決策樹通常都是CART。
實際上GBDT和AdaBoost的主要區別就在於AdaBoost是在每一次迭代中修改樣本權重來使得後一次的樹模型更加關注被分錯的樣本,而GBDT則是後一次樹模型直接去擬合殘差。這篇博客主要講解的內容有:
- 提升樹算法
- 梯度提升樹算法
- GBDT的優缺點
- GBDT的改進算法
一、提升樹算法
在前面介紹AdaBoost的時候,講了提升方法實際上就是加法模型和前向分佈法。提升樹算法那也採用前向分步法,首先初始提升樹 f0(x)=0,第m步的模型是
fm(x)=fm−1(x)+T(x;Θm)(1)
其中,fm−1(x)表示當前模型,目標是通過經驗風險極小化確定下一顆決策樹的參數Θm,
Θ^m=argΘmmini=1∑NL(yi,fm−1(xi)+T(xi;Θm))(2)
對於提升樹而言,分類問題使用的損失函數是指數函數,迴歸問題使用的是均方誤差。我們這裏主要回歸問題。
對於一個訓練集T={(x1,y1),(x2,y2),...,((xN,yN)},如果將輸入空間劃分爲J個互不相交的區域R1,R2,...,RJ,並且在每個區域上確定輸出的常量cj(看了CART的博客我們知道這個其實就是結點分裂後某個分支包含的樣本的真實值的平均值),則樹可表示爲:
T(x;Θ)=j=1∑JcjI(x∈Rj)(3)
其中,參數Θ={(R1,c1),(R2,c2),....,(RJ,cJ)},表示空間劃分和各區域上的常數(預測值),J是葉結點的個數。
對於迴歸問題,當損失函數爲均方誤差時,
L(y,f(x))=(y−f(x))2(4)
即,
L(y,fm−1(x)+T(x;Θm))=[y−fm−1(x)−T(x;Θm)]2=[r−T(x;Θm)]2(5)
其中,r=y−fm−1(x) 爲當前模型擬合數據的殘差,也就是說對迴歸問題的提升樹而言,下一次迭代中模型只需要擬合當前模型的殘差即可。上面說了這麼一堆,直接來看提升樹的算法吧,可能更清晰點。
下面直接上例子,一直覺得舉例子是最容易讓人懂得,文字描述太扯淡,又不是寫論文,搞這些形式化的文字意義不大。
數據集爲(摘自李航《統計學習方法》,注,李航的書並未給出特徵,只給出了x的取值範圍,我這裏把它給的切分點設置成了特徵,這樣最後結果保持不變):
樣本編號 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
xi(1) |
1.5 |
2.5 |
3.5 |
4.5 |
5.5 |
6.5 |
7.5 |
8.5 |
9.5 |
10.5 |
yi |
5.56 |
5.70 |
5.91 |
6.40 |
6.80 |
7.05 |
8.90 |
8.70 |
9.00 |
9.05 |
假設我們採用提升樹模型去學習這個迴歸問題,ps:由於這個數據集共10個樣本,每個樣本只有一個特徵,但是實際上顯然數據集不可能特徵是一維的,因此尋找最優特徵和最優切分點雙重for循環即可。我們這裏由於特徵是一維的,因此只要找到最優切分點即可。因此提升樹裏的基分類器實際上就是個CART,因此查找最優特徵和最優切分點過程就是CART的過程。下面是計算過程:
第一步, 即 m=1時:
- 當切分點爲s=1.5時,R1={1},R2={2,3,...,10},此時c1=5.56,c2=7.5,此時誤差m(1.5)=15.72
- 當切分點爲s=2.5時,R1={1,2},R2={3,...,10},此時c1=5.63,c2=7.73,此時誤差m(2.5)=12.08
- 當切分點爲s=3.5時,R1={1,2,3},R2={4,...,10},此時c1=5.72,c2=7.98,此時誤差m(3.5)=8.36
- 當切分點爲s=4.5時,R1={1,...,4},R2={5,...,10},此時c1=5.89,c2=8.25,此時誤差m(4.5)=5.78
- 當切分點爲s=5.5時,R1={1,...,5},R2={6,...,10},此時c1=6.07,c2=8.54,此時誤差m(5.5)=3.91
- 當切分點爲s=6.5時,R1={1,....,6},R2={7,...,10},此時c1=6.24,c2=8.91,此時誤差m(6.5)=1.93
- 當切分點爲s=7.5時,R1={1,....,7},R2={8,9,10},此時c1=6.62,c2=8.92,此時誤差m(7.5)=8.01
- 當切分點爲s=8.5時,R1={1,....,8},R2={9,10},此時c1=6.88,c2=9.03,此時誤差m(8.5)=11.74
- 當切分點爲s=9.5時,R1={1,....,9},R2={10},此時c1=7.11,c2=9.05,此時誤差m(9.5)=15.74
把上面的誤差放到一張表裏,看的更清晰點。
切分點 |
1.5 |
2.5 |
3.5 |
4.5 |
5.5 |
6.5 |
7.5 |
8.5 |
9.5 |
誤差(均方差) |
15.72 |
12.08 |
8.36 |
5.78 |
3.91 |
1.93 |
8.01 |
11.74 |
15.74 |
能夠看出當切分點爲6.5時,誤差最小,所以6.5爲最優切分點。此時c1=6.24,c2=8.91,所以迴歸樹T1(x)爲:
T1(x)={6.248.91x≤6.5x>6.5
所以,提升樹模型f1(x)=T1(x),那麼用這個模型去擬合訓練樣本,我們能夠算出預測值與真實值之間的誤差也就是殘差,如下表所示:
樣本編號 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
真實值yi |
5.56 |
5.70 |
5.91 |
6.40 |
6.80 |
7.05 |
8.90 |
8.70 |
9.00 |
9.05 |
殘差 |
-0.68 |
-0.54 |
-0.33 |
0.16 |
0.56 |
0.81 |
-0.01 |
-0.21 |
0.09 |
0.14 |
此時,損失(均方誤差)爲:
L(y,f1(x))=i=1∑10(yi−f1(x))2=1.93
第二步,即 m=2時,求 T2(x),求得方法與求T1(x)一樣,只不過T1(x)擬合的是yi,而T2(x)擬合的是上表中的殘差,求最後劃分點的過程我這裏就省略了,最優劃分點爲s=3.5,即
T2(x)={−0.520.22x≤3.5x>3.5
則,樹模型f2(x)爲:
f2(x)=f1(x)+T2(x)=⎩⎨⎧5.726.469.13x≤3.53.5<x≤6.5x>6.5
注意看下分段函數的相加。
用f2(x)擬合訓練樣本loss爲:
L(y,f2(x))=i=1∑10(yi−f2(x))2=0.79
第三步,即 m=3 時,有
T3(x)={0.15−0.22x≤6.5x>6.5
f3(x)=f2(x)+T3(x)=⎩⎨⎧5.876.618.91x≤3.53.5<x≤6.5x>6.5
loss爲:L(y,f3(x))=0.47。
第四步,即 m=4 時,有
T4(x)={−0.160.11x≤4.5x>4.5
f4(x)=f3(x)+T4(x)=⎩⎪⎪⎨⎪⎪⎧5.716.456.729.02x≤3.53.5<x≤4.54.5<x≤6.5x>6.5
loss爲:L(y,f4(x))=0.3。
第五步,即 m=5 時,有
T5(x)={0.07−0.11x≤6.5x>6.5
f5(x)=f4(x)+T5(x)=⎩⎪⎪⎨⎪⎪⎧5.786.526.798.91x≤3.53.5<x≤4.54.5<x≤6.5x>6.5
loss爲:L(y,f5(x))=0.23。
第六步,即 m=6 時,有
T6(x)={−0.150.04x≤2.5x>2.5
f6(x)=f5(x)+T6(x)=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧5.635.826.566.838.95x≤2.52.5<x≤3.53.5<x≤4.54.5<x≤6.5x>6.5
loss爲:L(y,f6(x))=0.17。
能夠看出隨着迭代的進行,誤差時不停地往下降得。
假設此時已經滿足誤差要求或者迭代次數夠了,那麼最終的提升樹模型即爲f6(x)。
二、梯度提升樹算法
從上面的提升樹算法來看,當我們的損失函數時平方誤差或者指數損失函數時,每一步的優化都很簡單。但是如果損失函數換做一般函數再去優化就不容易,所以有了梯度提升算法,其實就是利用最速下降法,也就是損失函數的負梯度作爲提升樹迴歸算法中的殘差近似值,去擬合一個迴歸樹。梯度爲:
−[∂f(xi)∂L(y,f(xi))]f(x)=fm−1(x)
但是這裏有個問題,我們熟悉的lr和神經網絡中採用梯度下降來優化,而這裏採用梯度提升,這二者之間到底有什麼關聯?這個問題我們待會再講,先來看下梯度提升算法:
前面留了個問題就是梯度提升和梯度下降的區別與聯繫是什麼?其實兩者都是在迭代過程中,利用損失函數相對於模型的負梯度方向來對當前模型進行更新,只不過在梯度下降中,模型是以參數話表示,因此模型的更新等價於參數的更新。而在梯度提升中,模型並不需要進行參數化表示,而是直接定義在函數空間中。
三、GBDT優缺點
優點:
- 泛化能力和表達能力都很好,因此是被使用最廣的算法之一。
- 具有較好的可解釋性和魯棒性,能夠自動發現特徵之間的高階關係,並且不需要對數據進行歸一化等處理。
缺點:
- 只能處理低維稠密的數據,對高維稀疏的數據表現較差。
- 處理類別特徵效果沒有數值型特徵好,因此常被用於迴歸任務。
- 因爲boosting算法因此訓練過程是串行的,關於這一點,xgboost對gbdt的重要改進就在這個地方。
四、GBDT的改進算法
對GBDT的改進最出名的是陳天奇的XGBoost,其對gbdt進行了大量的改進,如:
- 原始的GBDT基於經驗損失函數的負梯度來構造新的決策樹,只能在決策樹構造完後進行後剪枝。而XGBoost直接在構建階段就加入了正則項。
- GBDT在梯度下降時使用了代價函數的一階導數,而XGboost對代價函數進行二階泰勒展開,可以同時使用一階導數和二階倒數。
- GBDT使用CART作爲基分類器,XGBoost支持多種類型的基分類器。
- GBDT在每輪迭代時使用全部數據,而XGBoost則採用了與隨機森林相似的策略,對數據進行採樣。
- GBDT無法對缺失值進行處理,XGBoost可以自動學習出缺失值的處理。
後來MSRA的劉鐵巖組也對GBDT做了改進,即lightGBM。這個算法無論訓練速度和精讀方面都要比XGBoost要好些。此外,還有俄羅斯搜索巨頭提出的catBoost,似乎效果並沒有lightGBM好,關於XGBoost,lightGBM,catBoost的實驗對比,可參考文章:大戰三回合:XGBoost、LightGBM和Catboost一決高低 | 程序員硬核算法評測,這篇文章也印證了無論在速度還是準確率方面lightGBM都是有優勢的。
參考文獻
[1]: 李航《統計學習方法》
[2]: 諸葛越等《百面機器學習》
[3]:大戰三回合:XGBoost、LightGBM和Catboost一決高低 | 程序員硬核算法評測