集成學習-xgboost


xgboost是個准確率很高的集成學習框架,在很多比賽中成績優異。

 

大多數的集成學習都使用決策樹作為基分類器,主要是因為本身要訓練多個分類器,而決策樹速度很快,總體時間相對較少。

 

決策樹

在講xgboost之前,先描述一下決策樹,后面要用到這些符號

決策樹是把輸入x映射到一個葉節點中,這個過程我們記為q(x)

葉節點總數記為T,每個葉節點有個標簽(分類)或者預測值(回歸)w,即W=[w1,w2,...wT]

那么決策過程就是 f(x)=W[q(x)],記為wq(x)

 

決策樹的復雜度

決策樹很容易過擬合,過擬合是因為樹太深,模型過於復雜,限制過擬合主要是避免樹太深,可以限制葉節點的個數不能太多,也可以限制葉節點中樣本數不能太少,當然還有很多方法,

這里我們提出一個概念叫樹的復雜度,可以用葉節點的個數T和葉節點的標簽w來衡量,標簽w可以理解為節點中樣本較多,取平均會比較平滑,類似於 batch,

當然也可以用其他方式來衡量

 

xgboost通俗理解

本文以xgboost回歸為例進行講解

單個決策樹很難保障准確率,假設單個決策樹預測為y’,真實值為y,於是產生了一個誤差y-y',

xgboost針對這個誤差又建立了一棵決策樹,分析誤差產生的原因,從而彌補這個誤差,新的決策樹又會產生一個誤差,那么繼續建立一棵決策樹,如此迭代下去,這就是xgboost的大致過程。

 

這個過程好比我們寫代碼,先大致寫個框架,運行一下,看看哪不對,改一下,再運行一下,看看哪不對,再改一下,如此迭代,直至完全正確。

注意我們寫代碼時很少一下從頭寫到尾,因為這樣很不方便調試,如果錯誤太多,還不如重新寫,

對應到決策樹就是樹太深,過擬合,可能需要重新訓練,所以xgboost每一棵樹不能太深,這個例子不太合適,只是幫助理解

 

假設決策樹的預測為y',真實值為y,我們把誤差記為 l(y, y'),為了約束決策樹的復雜度,xgboost加上了正則項,我們用 Ω(f) 來表示,f代表決策樹

xgboost需要建立多棵決策樹,假設y'初始值為0,即瞎猜,沒有任何預測時為0,那么整個過程如下

i表示樣本,t表示第幾棵樹,yt表示前t棵樹的預測值,ft(x)表示新建的第t棵樹的預測值,

最終的預測值就是

k表示決策樹的個數。

 

建樹原則

那么問題來了,如何建樹?

普通的決策樹是利用信息增益、信息增益率或者基尼系數來建樹,那么xgboost建樹的指標是什么呢?

 

樹的損失函數

 之前說決策樹有個損失函數

n表示樣本數

根據經驗,我們需要使得損失函數最小,這就是建樹的原則。

 

那么怎么最小化損失函數呢?正常我們都會有個線性變換、激活函數,這里是一棵樹,怎么辦呢? 可能一時半會真想不到,先把公式變換一下吧

這個 constant 就是前t-1棵樹的復雜度,Ω (ft)是第t棵樹的復雜度。

 

假設l損失為均方差,上式變為

這里重新回憶一下,xgboost是一棵樹一棵樹的建立,也就是說在建立第t棵樹時,第t-1棵樹的預測值是已知的,也就是上式中 y, yt-1是已知的,故其運算值是常數,所以上式是這樣的

 

注意xgboost有個特點就是允許自定義損失函數,那么如果我們定義的損失函數不是均方差,那是不是得重新研究一下算法呢? 是的,確實要重新研究,但是xgboost為了避免這種麻煩,采用了損失函數的二階近似

二階Taylor展開

這里簡單介紹下

泰勒級數:把非線性函數f(x)=0在x0處展開成泰勒級數,注意x0是個已知數

然后取前3項作為近似值。

 

損失函數 l(y,yt-1+ft(x)) 是關於 yt-1+ ft(x) 的方程,yt-1+ ft(x)對應為泰勒展開中的x,yt-1是常數,對應為泰勒展開中的x0

所以損失函數 l(y,yt-1+ft(x)) 二階近似為

注意這里是對  l(y,yt-1+ft(x))  的展開。

這里需要理解下gi,hi是什么東西?貌似不是很清楚。

我們以均方差為例來看下

可以看到gi和hi就是損失函數對 預測值 的一階導和二階導,

而且gi和hi可以並行計算,並且是根據上一棵樹來計算的,也就是在新建樹時,他們是已知值。

 

樹損失函數展開為

去掉常數項

 

樹模型 正則化 Ω(ft)

前面說到決策樹的復雜度,假如用決策樹的葉節點數T和葉節點的預測值w來對樹進行正則化的,當然你也可以自定義其正則化的方式,合理即可,

T盡量少,w盡量平滑,所以

γ λ 是懲罰系數,需要自己定義,γ 越大,表示數結構越簡單,其對較多葉節點的樹(整棵樹的葉節點)懲罰越大,λ 同理。

這種正則方式被作者證明效果很好。

樹損失函數變形

 ft(x)=wq(x)

故樹損失函數變為

這樣的式子真的沒法處理,需要進一步變換

先看這張圖

可以看到T個葉節點中包含了所有樣本,也就是說遍歷葉節點可以獲取所有樣本,且同一個葉節點中樣本的預測值即wq(x)相同,

那么上式可以轉化為

 Ij表示第j個葉節點

注意,對於一棵確定的樹,G H 都是確定的,λ也是確定的,所有上式是一個關於w的二次函數,方程的解是 -b/2a,解帶入方程就是二次曲線的最小值

如果能使損失最小,那就是最好的樹。

obj 可以理解為樹的錯誤率,錯誤率越小越好。w就是預測值。

這就對應了信息增益等指標,就是分裂的評價指標,選擇obj最小的屬性進行分裂。

 

 大致如圖所示

 

這里稍微總結一下:

xgboost在上一棵樹的基礎上,新建一棵樹,這棵樹根據上一棵樹的一階導和二階導確定最優的分裂方式。

 

建樹

回憶一下傳統的決策樹如何建立,以id3為例,先根據一定的原則逐個按屬性分裂,然后計算分裂前后的信息增益,選擇增益最大的屬性進行分裂。

xgboost貌似也是這個邏輯,因為沒有其他好辦法。

逐個按屬性進行分裂,計算分裂前后的的損失(錯誤率),相減,取損失為正/負的,看誰減誰。

 

 在分的屬性中選擇絕對值最大的,這里理解就好,語言表述會有些繞。

 

分裂節點

那按屬性怎么分裂?方法幾乎無限多,枚舉肯定不現實。

回憶一下傳統id3決策樹,屬性分裂有離散和連續之分,離散按屬性值划分,連續只能二划分,排序,每兩個值之間取個數(如均值)進行划分,

xgboost的屬性是離散還是連續呢? 理論上也是都可以,不過回歸應該是連續的。

 

xgboost在分裂時會防止過擬合,所以它盡可能的會減少葉節點的數量,也就是每次只進行2分裂,所以xgboost回歸對應的基決策樹是cart決策樹。

實際分裂也大致等同於cart決策樹,每次分裂都會計算損失

 

精確搜索法

 怎么理解呢?大致思路等同於連續值處理

 

 

但是當樣本太大時,這種方法也會很慢,於是作者提出了一種加速方法

近似搜索法

思路大致同精確搜索,只是在確定分裂點時,不是逐個探索,而是在對特征進行排序后,找出幾個區間,作為分裂點

如先觀察特征的分布情況,划分區間,再分裂。

 

具體作者又提出了一些選擇

全局近似:即在訓練前就確定分裂點,后面每棵樹都用這些分裂點,這樣提出候選分裂點的次數少,而每棵樹探索的分裂點多,因為這種方法往往要多設一些分裂點,不然到后面就分不開了

局部近似:即每次建樹時重新確定分裂點,這種方法每次嘗試的少,對層數較深的樹比較合適

 

作者做過如下嘗試

桶的個數等於 1 / eps, 可以看出:

  • 全局切分點的個數夠多的時候,和Exact greedy算法性能相當。
  • 局部切分點個數不需要那么多,因為每一次分裂都重新進行了選擇。

======================== xgboost 進階 ========================

步長

xgboost也可以加入步長,這也是防止過擬合的好方法

yt=yt-1+ηft(x)

η通常取0.1

yt-yt-1是殘差,ηft(x)可以理解為在梯度上的學習,逼近目標值

 

雙隨機

xgboost還借鑒了隨機森林的雙隨機處理方式,進一步防止過擬合,並加速訓練和預測過程

 

xgboost實例

上文以回歸為例進行原理描述,這里以分類為例進行實例解析

 

數據集

15個樣本,2個特征

模型描述:基決策樹深度max_depth為3,共2棵樹num_boost_round=2,學習率eta=0.1,正則參數γ=0,λ=1,某損失函數(這不是重點,因為參考文獻這里做的好像不對,所以我沒有用它的)

可以假設

損失函數一階導 gi=yi,pred-y

損失函數二階導 hi=yi,pred*(1-yi,pred)

 

建第一棵樹

因為在分裂過程中要計算每個節點的G H,而G H 就是節點中樣本的g h 的和,故先把每個樣本的g h求出來。

g h 是上一棵樹的預測結果,這里是第一棵樹,沒有之前的預測結果,所以需要初始化一個結果,這里是01分類,我們初始化全部為0.5,當然其他也行

注意這里我們假設0.5是經過分類激活函數sigmoid后的值,是個概率值,因為經過sigmoid的值才能直接和真實標簽作差,這點很重要,后面會用到,當然你也可以假設0.5是不經過sigmoid的值,這里理解就好,往后面看會理解的

根據一階導二階導公式計算出所有樣本的g h,如下圖

比如計算ID=1的樣本y=0, g=0.5,0=0.5,h=0.5*(1-0.5)=0.25

 

下面開始分裂,目標是看看按哪個屬性進行分裂增益最大

建造第一層

遍歷屬性,首先是第一個屬性

第一個屬性值排序 [1,2,3,6,7,8,9,10] 共8個值,

以1為閾值分裂,小於1為一邊,不小於1為另一邊,左邊為空,右邊為全部,gain=0

以2為閾值分裂,小於2為一邊,不小於2為另一邊,左邊為[1,4],右邊為[2,3,5,6,7,8...15],GL=0,HL=0.5,GR=-1.5,HR=3.25,gain=0.05572

其余類似,最終結果如下圖

可以看到最大增益為0.615,對應分裂點為x<10

同樣步驟處理第二個特征,得到結果如下圖

可以看到最大增益為0.2186,對應分裂點x<0

明顯特征1的增益大於特征2的增益,所以按特征1進行分裂。

建造第二層

左子節點樣本為[1,2,3,4,5,6,7,8,9,10,11,12,14,15]

右子節點樣本為[13]

右邊只有1個節點,不可再分,那么該節點的預測值為

即 w=-0.4

左子節點按照第一層的方法划分,得到如下兩個表

按特征2進行分裂,分裂點為x<2

第一棵樹建造完畢

這里解釋下第一層右子節點預測值為-0.04,但是上面計算出來是-0.4呀,這里相當於直接乘上了學習率0.1,后面樹累加的時候就不用乘了

注意這里葉子節點上的值是沒有經過sigmoid的值

 

建第二棵樹

第二棵樹的構造方法與第一棵樹完全相同,只是第一棵樹的基礎值為初始化設定的,而第二棵樹的基礎值為第一棵樹的預測結果,正是這個原因,在分裂計算增益尋找分裂點時兩棵樹才不相同。

那第一棵樹的預測結果是什么呢?

是前1棵樹的結果相加,即 f0+f1,但是f0是經過sigmoid的值,f1是沒經過sigmoid的值,而我們需要的是沒經過sigmoid的值,

所以需要把f0即初始化的0.5還原成沒經過sigmoid的值,即已知函數和函數值,求x,很簡單,x=0,故第一棵樹的預測值為0+wq(x),然后需要經過sigmoid

*************** 注意重中之重 ***************

每棵樹的初始值是經過sigmoid函數的,因為要與真實標簽作差

每棵樹的輸出值是沒有經過sigmoid函數的,這樣才能與之前的輸出值相加

同理得到了第二棵樹

這樣最后一棵樹的結果即為預測值,當然分類要經過sigmoid函數。

至此模型完畢。

 

 

參考資料:

https://www.jianshu.com/p/7467e616f227

https://xgboost.readthedocs.io/en/latest/tutorials/model.html

https://blog.csdn.net/qq_22238533/article/details/79477547    手擼實例

https://www.hrwhisper.me/machine-learning-xgboost/    此文章還有很多我這里沒講到


免責聲明!

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



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