機器學習演算法(15)之Xgboost演算法

不曾走遠~發表於2018-09-11

前言:前一篇文章對boosting的兩個方法做了闡述,這篇文章將會是對前兩篇文章的深化,談的是一個更加優化了的boostIng演算法,自從2014年9月份在 Kaggle 的希格斯玻色子機器學習大賽中奪魁以來,XGBoost 與深度學習兩個演算法壟斷了 Kaggle 大賽的大部分冠軍。現在Kaggle 大賽的情況基本是這樣的,凡是非結構化資料相關,比如語音、影像,基本都是深度學習獲勝凡是結構化資料上的競賽,基本都是 XGBoost 獲勝


1、回顧下GB、GBDT

        GBDT和xgboost在競賽和工業界使用都非常頻繁,能有效的應用到分類、迴歸、排序問題,因此這裡嘗試一步一步梳理GB、GBDT、xgboost,它們之間有非常緊密的聯絡,GBDT是以決策樹(CART)為基學習器的GB演算法,xgboost擴充套件和改進了GDBT,xgboost演算法更快,準確率也相對高一些。  

1.1、Gradient boosting(GB)

        機器學習中的學習演算法的目標是為了優化或者說最小化loss Function, Gradient boosting的思想是迭代生多個(M個)弱的模型,然後將每個弱模型的預測結果相加,後面的模型F_{m+1}(x)基於前面學習模型的F_{m}(x)的效果生成的,關係如下:

                                                 F_{m+1}(x)=F_{m}(x)+h(x),1\leq m\leq M

GB演算法的思想很簡單,關鍵是怎麼生成h(x)?

      如果目標函式是迴歸問題的均方誤差,很容易想到最理想的h(x)應該是能夠完全擬合 y-F_{m}(x),這就是常說基於殘差的學習。殘差學習在迴歸問題中可以很好的使用,但是為了一般性(分類,排序問題),實際中往往是基於loss Function 在函式空間的的負梯度學習,對於迴歸問題1/2(y-F(x))^{2}殘差和負梯度也是相同的。L(y,f)中的f,不要理解為傳統意義上的函式,而是一個函式向量f(x_{1}),f(x_{x}),f(x_3),...f(x_n)向量中元素的個數與訓練樣本的個數相同,因此基於Loss Function函式空間的負梯度的學習也稱為“偽殘差”。

GB演算法的步驟:

1.初始化模型為常數值:

                                    

2.迭代生成M個基學習器

          1)計算偽殘差

                                  

          2.基於\{(x_i, r_{im})\}_{i=1}^n生成基學習器\! h_m(x)

          3.計算最優的\! \gamma_m

                                   

         4.更新模型

                                  

1.2、Gradient boosting Decision Tree(GBDT)

       GBDT的原理篇在上一篇已經闡述過,這裡稍微總結性下,GBDT是GB和DT的結合。要注意的是這裡的決策樹是分類迴歸樹(是一種二叉樹),GBDT中的決策樹是個弱模型,有些GBDT的實現加入了隨機抽樣(subsample 0.5<=f <=0.8)提高模型的泛化能力。通過交叉驗證的方法選擇最優的引數。

因此GBDT實際的核心問題變成怎麼基於\{(x_i, r_{im})\}_{i=1}^n使用CART迴歸樹生成\! h_m(x)

2、Xgboost演算法

       前面已經說過,xgboost可以說整合思想達到頂峰的一個模型,至少目前是這樣,所以我們學習機器學習演算法, 掌握這個是很有必要的。順帶提一下,Xgboost目前scikit-learn中沒有實現,需要我們自行安裝Xgboost,可以通過python呼叫,我自己也記錄了一個純小白都能安裝好的方法

  • 全稱:eXtreme Gradient Boosting(極值梯度提升演算法)
  • 作者:陳天奇(華盛頓大學博士) 
  • 基礎:GBDT 
  • 所屬:boosting迭代型、樹類演算法。 
  • 適用範圍:分類、迴歸等
  • 優點:速度快、效果好、能處理大規模資料、支援多種語言、支援自定義損失函式等等。

2.1、與GBDT的區別:

首先我們先在大體上對xgboost有個大致的印象,然後我們在對其原理做詳細的闡述。

      • XGBoost的基學習器除了可以是CART(這個時候就是GBDT)也可以是線性分類器,而GBDT只能是CART。
      • XGBoost在代價函式中加入了正則項,用於控制模型的複雜度(正則項的方式不同,如果你仔細點話,GBDT是一種類似於縮         減係數,而XGBoost類似於L2正則化項)。
      • XGBoost借鑑了隨機森林的做法,支援特徵抽樣,不僅防止過擬合,還能減少計算
      • XGBoost工具支援並行化
      • 綜合來說Xgboost的運算速度和演算法精度都會優於GBDT

2.2 Xgboost演算法原理

       Xgboost是GB演算法的高效實現,xgboost中的基學習器除了可以是CART也可以是線性分類器(gblinear)。下面所有的內容來自原始paper,包括公式。

1)樹的結構

     我們從單一的樹來考慮。對於其中每一棵迴歸樹,其模型可以寫成:f_{t}(x)=w_{q_{x}},w\in R^{T},q:R^{d}\rightarrow {1,2,...T}                      

                    

      其中\omega為葉子節點的得分值,q(x)表示樣本x對應的葉子節點。T為該樹的葉子節點個數。

      因此,在這裡。我們將該樹的複雜度寫成:\Omega (f_{t})=\gamma T+1/2\lambda \sum_{j=1}^{T}w_{j}^{2}

      其中,γγ為L1L1正則的懲罰項,λλ為L2L2正則的懲罰項

      複雜度計算例子如下:

             

2) 損失函式

       前面已經說過,為了一般性,實際中往往是基於loss Function L(y,f)在函式空間的的負梯度學習,對於迴歸問題1/2(y-F(x))^{2}殘差和負梯度也是相同的。和傳統的boosting tree模型一樣,xgboost的提升模型也是採用的殘差(或梯度負方向),不同的是分裂結點選取的時候不一定是最小平方損失。 

                                                          

對目標函式的改寫:

       

       最終的目標函式只依賴於每個資料點的在誤差函式上的一階導數和二階導數。這麼寫的原因很明顯,由於之前的目標函式求最優解的過程中只對平方損失函式時候方便求,對於其他的損失函式變得很複雜,通過二階泰勒展開式的變換,這樣求解其他損失函式變得可行了。

      我相信到這裡肯定都沒有問題,接下來的理解是整個損失函式的難點,我自己開始學的時候想了一些時間,接下來我儘量用白話來敘述。

1)對f_{t}(x_{i})的理解:在上面我們已經說了,當一個樣本進來的時候,不管是迴歸問題還是分類問題,你最終都會掉到葉子結點上,而每顆樹的每個葉子節點都會對應有一個得分(想象一下回歸問題,每個葉子節點對應的是落入該葉子結點的所有訓練樣本的均值),所以f_{t}(x_{i})可以理解為一個樣本在t輪最終的得分函式。

2)對g_{i},h_{i}的理解:其實這個的理解,我最初鑽了牛角尖,其實只要當我們的損失函式一旦確定下來(理解的前提),這個求導就和我們高數中的求導一回事啦,只不過表示式看起來很唬人。

3)目標函式全部轉換成在第t棵樹葉子節點的形式。從求和符號我們可以看出,是在對每個樣本求損失,我們在第一點就已經說了,第i個樣本最終都會落到樹的葉子結點中去的,只是不同的葉子節點,你會取不同的值罷了。那我們能不能講對樣本的損失轉移到對葉子結點中再求損失呢(後話,這個就是這麼做的),\sum_{i=1}^{n}g_{i}f_{t}(x_{i})+1/2h_{i}f_{t}^{2}(x_{i}) 可以看做是每個樣本在第t棵樹的葉子節點得分值相關函式的結果之和,所以我們也能從第t棵樹的葉子節點上來表示。

              

      這裡也在解釋下,w_{q_{x}}描述了一整顆樹的模型,他當然能分解成每個葉子結點的集合啦,而w_{j}剛好是每個葉子節點的得分函式,這兩個於是就可以相互轉化了。

其中T為第t棵樹中總葉子節點的個數,I_{j} = {i|q(x_{i}=j)表示i樣本落在第j個葉子節點上,w_{j}為第j個葉子節點的得分值。

在這裡,令

                

w_{j}求偏導,並使其導函式等於0,則有:

                                             

             

到此,損失函式的推導完成。

3)樹結構的打分函式

      Obj代表了當指定一個樹的結構的時候,在目標上面最多減少多少。結構分數(structure score)

       

       xgboost演算法的步驟和GB基本相同,都是首先初始化為一個常數,gb是根據一階導數ri,xgboost是根據一階導數gi和二階導數hi,迭代生成基學習器,相加更新學習器。

對於每一次嘗試去對已有的葉子加入一個分割

                 

       這樣就可以在建樹的過程中動態的選擇是否要新增一個結點。  聯想決策樹中資訊增益,這裡的原理類似。這一步實質上是為了尋找分裂結點的候選集。

       如何高效地列舉所有的分割呢?我假設我們要列舉所有x < a 這樣的條件,對於某個特定的分割a我們要計算a左邊和右邊的導數和。

                   

我們可以發現對於所有的a,我們只要做一遍從左到右的掃描就可以列舉出所有分割的梯度和G_{L}G_{R}。然後用上面的公式計算每個分割方案的分數就可以了。

xgboost演算法虛擬碼如下:

            

3、Xgboost演算法引數

XGBoost的作者把所有的引數分成了三類:

  1. 通用引數:巨集觀函式控制。
  2. Booster引數:控制每一步的booster(tree/regression)。
  3. 學習目標引數:控制訓練目標的表現。

3.1通用引數

這些引數用來控制XGBoost的巨集觀功能。

1、booster[預設gbtree]

  • 選擇每次迭代的模型,有兩種選擇: 
    gbtree:基於樹的模型 
    gbliner:線性模型

2、silent[預設0]

  • 當這個引數值為1時,靜默模式開啟,不會輸出任何資訊。
  • 一般這個引數就保持預設的0,因為這樣能幫我們更好地理解模型。

3、nthread[預設值為最大可能的執行緒數]

  • 這個引數用來進行多執行緒控制,應當輸入系統的核數。
  • 如果你希望使用CPU全部的核,那就不要輸入這個引數,演算法會自動檢測它。

還有兩個引數,XGBoost會自動設定,目前你不用管它。接下來我們們一起看booster引數。

3.2 booster引數

儘管有兩種booster可供選擇,我這裡只介紹tree booster,因為它的表現遠遠勝過linear booster,所以linear booster很少用到。

1、eta[預設0.3]

  • 和GBM中的 learning rate 引數類似。
  • 通過減少每一步的權重,可以提高模型的魯棒性。
  • 典型值為0.01-0.2。

2、min_child_weight[預設1]

  • 決定最小葉子節點樣本權重和。
  • 和GBM的 min_child_leaf 引數類似,但不完全一樣。XGBoost的這個引數是最小樣本權重的和,而GBM引數是最小樣本總數
  • 這個引數用於避免過擬合。當它的值較大時,可以避免模型學習到區域性的特殊樣本。
  • 但是如果這個值過高,會導致欠擬合。這個引數需要使用CV來調整。

3、max_depth[預設6]

  • 和GBM中的引數相同,這個值為樹的最大深度。
  • 這個值也是用來避免過擬合的。max_depth越大,模型會學到更具體更區域性的樣本。
  • 需要使用CV函式來進行調優。
  • 典型值:3-10

4、max_leaf_nodes

  • 樹上最大的節點或葉子的數量。
  • 可以替代max_depth的作用。因為如果生成的是二叉樹,一個深度為n的樹最多生成n2n2個葉子。
  • 如果定義了這個引數,GBM會忽略max_depth引數。

5、gamma[預設0]

  • 在節點分裂時,只有分裂後損失函式的值下降了,才會分裂這個節點。Gamma指定了節點分裂所需的最小損失函式下降值。
  • 這個引數的值越大,演算法越保守。這個引數的值和損失函式息息相關,所以是需要調整的。

6、max_delta_step[預設0]

  • 這引數限制每棵樹權重改變的最大步長。如果這個引數的值為0,那就意味著沒有約束。如果它被賦予了某個正值,那麼它會讓這個演算法更加保守。
  • 通常,這個引數不需要設定。但是當各類別的樣本十分不平衡時,它對邏輯迴歸是很有幫助的。
  • 這個引數一般用不到,但是你可以挖掘出來它更多的用處。

7、subsample[預設1]

  • 和GBM中的subsample引數一模一樣。這個引數控制對於每棵樹,隨機取樣的比例。
  • 減小這個引數的值,演算法會更加保守,避免過擬合。但是,如果這個值設定得過小,它可能會導致欠擬合。
  • 典型值:0.5-1

8、colsample_bytree[預設1]

  • 和GBM裡面的max_features引數類似。用來控制每棵隨機取樣的列數的佔比(每一列是一個特徵)。
  • 典型值:0.5-1

9、colsample_bylevel[預設1]

  • 用來控制樹的每一級的每一次分裂,對列數的取樣的佔比。
  • 我個人一般不太用這個引數,因為subsample引數和colsample_bytree引數可以起到相同的作用。但是如果感興趣,可以挖掘這個引數更多的用處。

10、lambda[預設1]

  • 權重的L2正則化項。(和Ridge regression類似)。
  • 這個引數是用來控制XGBoost的正則化部分的。雖然大部分資料科學家很少用到這個引數,但是這個引數在減少過擬合上還是可以挖掘出更多用處的。

11、alpha[預設1]

  • 權重的L1正則化項。(和Lasso regression類似)。
  • 可以應用在很高維度的情況下,使得演算法的速度更快。

12、scale_pos_weight[預設1]

  • 在各類別樣本十分不平衡時,把這個引數設定為一個正值,可以使演算法更快收斂。

3.3學習目標引數

這個引數用來控制理想的優化目標和每一步結果的度量方法。

1、objective[預設reg:linear]

  • 這個引數定義需要被最小化的損失函式。最常用的值有: 
    • binary:logistic 二分類的邏輯迴歸,返回預測的概率(不是類別)。
    • multi:softmax 使用softmax的多分類器,返回預測的類別(不是概率)。 在這種情況下,你還需要多設一個引數:num_class(類別數目)。
    • multi:softprob 和multi:softmax引數一樣,但是返回的是每個資料屬於各個類別的概率。

2、eval_metric[預設值取決於objective引數的取值]

  • 對於有效資料的度量方法。
  • 對於迴歸問題,預設值是rmse,對於分類問題,預設值是error。
  • 典型值有: 
    • rmse 均方根誤差(∑Ni=1ϵ2N−−−−−√∑i=1Nϵ2N)
    • mae 平均絕對誤差(∑Ni=1|ϵ|N∑i=1N|ϵ|N)
    • logloss 負對數似然函式值
    • error 二分類錯誤率(閾值為0.5)
    • merror 多分類錯誤率
    • mlogloss 多分類logloss損失函式
    • auc 曲線下面積

python的Xgbosoost調參例項:推薦看  https://blog.csdn.net/han_xiaoyang/article/details/52665396

除此以外,xgboost除了原生版的呼叫以外,sklearn還為我們封裝了一個sklearn版本呼叫的方法,from xgboost import XGBClassifier,調參同樣可以借用網格搜尋的方法,這是一篇xgboost的網格搜尋的案例

4、小結

xgboost與gdbt除了上述的不同,xgboost在實現時還做了許多優化:(以下轉載於 機器學習系列(12)_XGBoost引數調優完全指南(附Python程式碼)

1)並行處理

  • XGBoost可以實現並行處理,相比GBM有了速度的飛躍
  • 不過,眾所周知,Boosting演算法是順序處理的,它怎麼可能並行呢?每一課樹的構造都依賴於前一棵樹,那具體是什麼讓我們能用多核處理器去構造一個樹呢?我希望你理解了這句話的意思。如果你希望瞭解更多,點選這個連結
  • XGBoost 也支援Hadoop實現。

2)高度的靈活性

  • XGBoost 允許使用者定義自定義優化目標和評價標準

3)缺失值處理

  • XGBoost內建處理缺失值的規則。
  • 使用者需要提供一個和其它樣本不同的值,然後把它作為一個引數傳進去,以此來作為缺失值的取值。XGBoost在不同節點遇到缺失值時採用不同的處理方法,並且會學習未來遇到缺失值時的處理方法。

4)剪枝

5)內建交叉驗證

  • XGBoost允許在每一輪boosting迭代中使用交叉驗證。因此,可以方便地獲得最優boosting迭代次數。
  • 而GBM使用網格搜尋,只能檢測有限個值。

 

參考資料:

https://www.cnblogs.com/wxquare/p/5541414.html

https://blog.csdn.net/a1b2c3d4123456/article/details/52849091

陳天奇的boosting tree的ppt:http://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf

sklearn版本呼叫的方法:XGBoost Python API Reference (official guide)

XGBoost 引數:http://xgboost.apachecn.org/cn/latest/parameter.html#

XGBoost-Python完全調參指南-引數解釋篇https://blog.csdn.net/wzmsltw/article/details/50994481

XGBoost引數調優完全指南(附Python程式碼)https://blog.csdn.net/han_xiaoyang/article/details/52665396

python 下實現xgboost 調參演示https://blog.csdn.net/weixin_41370083/article/details/79276887

XGBoost調參技巧(二)Titanic實戰Top9%https://blog.csdn.net/c2a2o2/article/details/77646025

 

相關文章