XGboost文獻學習筆記

查看原文:http://www.wyblog.cn/2016/11/25/xgboost%e6%96%87%e7%8c%ae%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/

XGboost的學習資料主要爲以下兩個。 其一是PPT資料:

http://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf

其二是論文資料:

https://arxiv.org/pdf/1603.02754v3

先看PPT,搞懂了XGboost的原理後,再看論文就輕鬆多了。

先總結


先總結下xgboost。實際上,xgboost全名叫Extreme Gradient Boosting,是由陳天奇大神開發的。從名字上來看,其實它屬於gradien tree的一個分支,它並不是和GBDT處於並列的關係,它是在GBDT上做了算法改進,使得算法適應新更強。那麼,具體改進了哪些地方呢?

  • 在模型上,xgboost的泛化能力更強,原因在於其損失函數的構建上。傳統的樹模型損失函數只考慮了經驗損失,即預測值與真實值得偏差作爲損失函數的目標,但xgboost在損失函數中加入了正則化項,用於對樹結構複雜度的控制,它包含了兩項,一項是葉子節點的個數T,另一項是葉子輸出score值ω的L2範數,它能夠有效地避免過擬合,這也正是文章中反覆提到的要平衡 bias-variance tradeoff,即預測準確性以及模型簡潔性之間的平衡。

  • 在損失函數上,傳統的GBDT採用的是一階導數,即用的梯度信息,而xgboost用了泰勒公式進行二階導數的展開,並且,在文章中提到了,損失函數其實是可以自定義的,可以用Square loss,可以用Logistic loss,這也正是它優點之一,scalable。

  • 在每一輪的迭代後,迭代出的樹都會被乘以一個小於1的權重ε,它是爲了給下一輪及以後的迭代預留大的空間,這其實就是學習速率問題。文獻中的建議是儘量減小這個權重ε,然後增大迭代的次數。

  • 對於稀疏的數據,以及可能有缺失項的數據,xgboost在學習時會給一個默認的分類方向。

  • xgboost支持並行及分佈式計算,並且以最少的資源使用進行計算,這對於處理大數據量以及提高計算速度有很大作用。這裏的並行計算的粒度並不在樹,每一顆樹還是串行迭代出來的,並行的粒度在於特徵值分割點的計算,它同時開幾個線程進行特徵分割點計算,大大加快了計算速度。

  • 在進行split點選取時,採用的是貪心算法,它總是去尋找當前迭代情況下的最優分裂點,爲了找到這個點,需要先將所有特徵的值進行排序,然後再計算每一種分裂可能,最後找出最優值。xgboost非常聰明的先把所有排序值給緩存下來,然後在後邊計算時直接調用就行,避免了每一次排序的麻煩。

算法原理


xgboost跟GBDT一樣,模型可以表示爲:$latex \hat {y_{i}} = \phi (X_{i}) = \sum_{k=1}^{K} f_{k} (X_{i}), \quad f_{k} \in F $ 其中,$latex F= (f(x)= \omega_{q(x)} ) \quad (q: R^{m} \rightarrow T , \omega \in R^{T})$ 它是由一連串樹串聯疊加而成。其中,q(x)是將實例映射到樹葉的函數,也就是代表了單棵決策樹,ω是對應樹葉的權重值,那麼,f(x)就是將實例x經過決策樹後,得到對應樹葉上的權值,最後的預測 $latex \hat {y_{i}}$ 就是將每一顆樹得到的權值相加,便是預測值了。注意,這裏描述的是普通boost tree的形式,xgboost做了一點改進就是在每一個棵迭代出的樹都乘以了一個小於1的ε後,才進行下一輪的迭代的,即$latex \hat {y}^{(t)}= \hat {y}^{(t-1)}+ \varepsilon f_{t}(x_{i}) $。 算法的loss function爲 $latex L(\phi)=\sum_{i}^{N} l ( y_{i} ,\hat {y_{i}^{(t)}} ) + \sum_{k} \Omega (f_{k}) $,其中,$latex \Omega (f) = \gamma T + \frac {1} {2} \lambda || \omega ^{2} || $。 以上損失函數中,第一項l代表預測的經驗風險,第二項Ω代表結構風險,其代表了模型的複雜度。T代表了樹的葉子節點個數,正則化參數λ可以避免模型的過擬合。對於目標函數的最優化,採用的是啓發式方法。 目標優化函數爲$latex L^{(t)} =\sum_{i=1}^{n} l(y_{i},\hat y_{i}^{(t-1)}+f_{t}(x_{i}))+\Omega (f_{t})$ ,其中 $latex \hat y_{i}^{(t-1)} $ 代表的是第i個訓練實例在第t-1輪迭代時的預測值。 考慮泰勒二階展開式,得到$latex L^{(t)} \approx \sum_{i=1}^{n}[ l(y_{i},\hat y_{i}^{(t-1)})+g_{i} f_{t}(x_{i}) + \frac {1}{2} h_{i} f_{i}^{2}(X_{i})]+ \Omega (f_{t}) $, 其中係數 $latex g_{i},h_{i}$,分別爲上一次損失函數對預測值的一階偏導與二階偏導數,即 $latex g_{i}=\frac {\partial_{l(y_{i},\hat y^{(t-1)})}}{\partial_{\hat y^{(t-1)}}} $,$latex h_{i}=\frac {\partial_{l(y_{i},\hat y^{(t-1)})}^{2}}{\partial_{\hat y^{(t-1)}}^{2}}$。 從這裏可以看到,gi與hi的值與損失函數的選取有關,例如,如果選取二次損失函數$latex l=(y-\hat y)^{2} $,那麼對它求一階與二階偏導,$latex g_{i}=2(\hat y^{(t-1)}-y_{i})$,$latex h_{i}=2$。 簡化L中固定的的常數項,損失函數最終可表示爲$latex \tilde {L} ^{(t)} = \sum_{i=1}^{n} [g_{i} f_{t}(X_{i}) + \frac {1}{2} h_{i} f_{i}^{2}(X_{i})]+ \Omega (f_{t}) +const$。

求得了損失函數表示形式,那麼就要開始分析如何來最優化損失函數了。從以上表達式可以看出,優化損失函數要考慮三個問題,一個是gi與hi的值,一個是樹的具體形式f(Xi),還有一個是結構風險Ω。下面一個一個分析。

hi與gi是什麼?

上文中已經分析了,hi與gi是經驗損失函數的一階偏導與二階偏導,它的計算式取決於我們選取的經驗損失函數,但是它的值卻與預測值有關,所以說,hi與gi實際上也取決於f(xi),在每一輪迭代樹時,它的值都會變化。

如何構造樹f(x)呢?

首先要重構一下損失函數。當訓練集實例被映射到每一片葉子後,訓練集就被分爲一塊一塊的了,定義每一篇葉子j爲 $latex I_{j}= (i|q(x_{i})=j) $,這個等式的意思是把第i個實例映射到第j片葉子上。然後,我們把損失函數改爲按葉子節點來計算損失的形式: $latex Obj^{(t)} = \sum_{i=1}^{n} [g_{i}f_{t}(x_{i})+\frac{1}{2}h_{i}f_{t}^{2}(x_{i})]+\Omega (f_{t})$ $latex ..\quad \quad =\sum_{i=1}^{n} [g_{i} \omega_{q(x_{i})}+\frac{1}{2}h_{i}\omega_{q_{(x_{i})}}^{2}]+\gamma T +\lambda \frac{1}{2} \sum_{j=1}^{T} \omega_{j}^{2}$ $latex ..\quad \quad =\sum_{j=1}^{T}=[(\sum_{i\in I_{j}}g_{i})\omega_{j}+\frac{1}{2}(\sum_{i\in I_{j}}h_{i}+\lambda)\omega_{j}^{2}+\gamma T$ $latex ..\quad \quad =\sum_{j=1}^{T}[G_{j}\omega_{j}+\frac {1}{2}(H_{j}+\lambda)\omega_{j}^{2}]+\gamma T$ 以上,Hj與Gj分別代表了第j片葉子上的所有實例的hi與gi之和。λ與γ分別爲正則化係數。ωj代表映射到第j片葉子上時,所得到的score。而我們要優化的,正是這個score。 考慮到二次函數$latex \frac {1}{2} ax^{2}+bx$,其最優解爲 $latex argmin_{x}=- \frac {b}{a} ,min_{x}= -\frac {1}{2} \frac {b^{2}}{a} $,所以,目標函數最優解爲: $latex Obj=- \frac {1}{2} \sum_{j=1}^{T} \frac {G_{j}^{2}}{H_{j}+ \lambda }+\gamma T $,當$latex \omega_{j}^{*}= - \frac {G_{j}}{H_{j}+ \lambda }$。 以上給出了構造boost樹的準則,即構造的樹的結構要使得Obj最小。 傳統方式上,可以枚舉出所有可能的樹的結構,然後去計算每種結構的Obj函數的值,找到最優結構後,再根據$latex \omega_{j}^{ * }$的公式,去計算每一片樹葉的score。但可預見的是,這幾乎是不可能實現的算法,樹的結構形式存在無數種可能性,計算量太大了。 所以,xgboost採用了貪心策略。每一棵樹都一層一層的增長,在某個feature處,是否split,取決於: $latex Gain = \frac {1}{2} [ \frac {(\sum_{i \in I_{L}} g_{i})^{2}}{ \sum_{i \in I_{L}} h_{i}+\lambda} + \frac {(\sum_{i \in I_{R}} g_{i})^{2}}{ \sum_{i \in I_{R}} h_{i}+\lambda} - \frac {(\sum_{i \in I} g_{i})^{2}}{ \sum_{i \in I} h_{i}+\lambda}]-\gamma$。 以上公式是在判斷,經過此處split後,與不split相比,是否能降低目標優化Obj函數的值,同時還要扣除增加樹葉帶來的風險γ(注意這個γ就是正則化項裏樹葉數量T的係數γ),如果能降低,那麼就split,否則就不變。 剩下的問題就是,如何以更好的方法去尋找split點了。 xgboost處理的方式是,預先對所有訓練實例的每個feature值進行排序,然後進行線性掃描,去尋找每個feature的最佳分割點,當然這裏Gain值有可能計算出來每個split點都是負值,自然地,這種情況下當前feature就不用作爲split節點了。經過以上處理,建立每一棵樹複雜度就變爲了O(d k nlogn),代表d個feature,k層樹,排序需要O(nlogn)的複雜度。xgboost在這裏進行了進一步優化,例如對缺失值進行默認參數處理,以及提前將所有特徵值排序並cache下來。 最後,爲了避免造成過擬合,除了正則化參數外還有其他方式。第一種是shrinkage,它在每一個被訓練出的樹上乘以一個參數η以削弱其影響,給後邊繼續訓練的樹以訓練空間。第二種方式是像隨機森林一樣,訓練時對特徵進行隨機採樣,這樣也加快了訓練速度。另外,如果一個樹深度過大,那麼可以進行剪枝,去掉那些Gain值小的分裂點。

查看原文:http://www.wyblog.cn/2016/11/25/xgboost%e6%96%87%e7%8c%ae%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/
發佈了84 篇原創文章 · 獲贊 26 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章