數學推導 + 純 Python 實現 XGBoost

2021-02-19 AI有道

自從陳天奇於2015年提出XGBoost以來,該模型就一直在各大數據競賽中當作大殺器被頻繁祭出。速度快、效果好是XGBoost的最大優點。XGBoost與GBDT同出一脈,都屬於boosting集成學習算法,但XGBoost相較於GBDT要青出於藍而勝於藍。XGBoost的全程為eXtreme Gradient Boosting,即極端梯度提升樹。要深入理解整個XGBoost模型系統,建議還是要認真研讀陳天奇的 XGBoost: A Scalable Tree Boosting System 論文,深入損失函數的推導,這樣才能更好的掌握XGBoost。本文僅對模型最重要的部分,即XGBoost損失函數的數學推導過程和結點分裂的增益計算方式進行闡述。既然XGBoost整體上仍然屬於GBDT系統,那麼XGBoost也一定是由多個基模型組成的一個加法模型,所以XGBoost可表示為:其中,  為損失函數的正則化項,表示全部  棵樹的複雜度之和,旨在防止模型過擬合。XGBoost來自於GBDT,同樣也適用前向分步算法,以第  步的模型為例,模型對第  個樣本  的預測值為:其中,  是由第    步的模型給出的預測值,作為一個已知常數存在,    是第  步樹模型的預測值。所以,目標函數可以改寫為:同時也可以對正則化項進行拆分,由於前 棵樹的結構已經確定,因此前   棵樹的複雜度之和也可以表示為常數:
然後我們使用二階泰勒公式(這裡需要大家回顧微積分相關知識),可以將損失函數改寫為:其中,  為損失函數的一階導,  為損失函數的二階導,需要注意的是這裡是對  求導。XGBoost相較於GBDT而言用到了二階導數信息,所以如果要自定義損失函數,首要的要求是其二階可導。將該二階泰勒展開式帶入前述推導的XGBoost損失函數中,可得損失函數的近似表達式:所以只需要求出每一步損失函數的一階導和二階導的值,然後最優化目標函數,就可以得到每一步的  ,最後根據加法模型得到一個boosting模型。然後重新定義一棵決策樹,其包括兩個部分:葉子結點的權重向量  和實例(樣本)到葉子結點的映射關係  (本質是樹的分支結構);和葉子權重    ,具體來說損失函數的複雜度由所有樹的葉子結點數和葉子權重所決定。數學表達如下式所示:然後我們對所有葉子結點進行重新歸組。將屬於第  個葉子結點的所有樣本  劃入到一個葉子結點的樣本集合中,即:  ,從而XGBoost的目標函數可以改寫為: :葉子結點    所包含樣本的一階偏導數累加之和,是一個常量; :葉子結點    所包含樣本的二階偏導數累加之和,是一個常量;將  和  帶入前述XGBoost損失函數,可得最終的損失函數表達式為:對於每個葉子結點   將其從目標函數中拆解出來,有:由前述推導可知,  和  相對於第  棵樹來說是可以計算出來的。所以該式就是一個只包含一個變量葉子結點權重  的一元二次函數,可根據最值公式求其最值點。當相互獨立的每棵樹的葉子結點都達到最優值時,整個損失函數也相應的達到最優。當樹結構固定的情況下,對上式求導並令其為0,可得最優點和最優值為:以上就是XGBoost完整的損失函數推導過程。基本框架仍然是GBDT框架,但XGBoost的最大特色是用到了損失函數的二階導數信息,目的就在於能夠更加準確的逼近真實損失。
下圖是XGBoost論文中給出的葉子結點權重計算:
根據二階導信息把XGBoost的優化推到了極為逼近真實損失的狀態,其結點分裂方式就跟CART樹的結點分裂方式本質上並沒有太大區別,但信息增益的計算方式有所不同。假設模型在某一節點完成特徵分裂,分裂前的目標函數可以寫為:如果增益Gain>0,即分裂為兩個葉子節點後,目標函數下降了,則考慮此次分裂的結果。實際處理時需要遍歷所有特徵尋找最佳分裂特徵。以上就是XGBoost模型核心數學推導部分。完整的XGBoost模型還有很多工程上的細節,這裡不做過多闡述,各位讀者最好把XGBoost論文認真研讀一遍。完整的XGBoost推導示意圖如下所示。
有了GBDT的算法實現經驗,XGBoost實現起來就並沒有太多困難了,大多數底層代碼都較為類似,主要是在信息增益計算、葉子得分計算和損失函數的二階導信息上做一些變動。同樣先列出代碼框架:

底層的決策樹結點和樹模型定義基本差別不大,具體這裡不再列出,可參考第15講GBDT實現方式。主要是繼承底層的樹結點和樹來定義XGBoost單棵樹和XGBoost樹模型擬合方式。
class XGBoostTree(Tree):    # 結點分裂    def _split(self, y):        col = int(np.shape(y)[1]/2)        y, y_pred = y[:, :col], y[:, col:]        return y, y_pred
# 信息增益計算公式 def _gain(self, y, y_pred): Gradient = np.power((y * self.loss.gradient(y, y_pred)).sum(), 2) Hessian = self.loss.hess(y, y_pred).sum() return 0.5 * (Gradient / Hessian)
# 樹分裂增益計算 def _gain_by_taylor(self, y, y1, y2): # 結點分裂 y, y_pred = self._split(y) y1, y1_pred = self._split(y1) y2, y2_pred = self._split(y2)
true_gain = self._gain(y1, y1_pred) false_gain = self._gain(y2, y2_pred) gain = self._gain(y, y_pred) return true_gain + false_gain - gain
# 葉子結點最優權重 def _approximate_update(self, y): # y split into y, y_pred y, y_pred = self._split(y) # Newton's Method gradient = np.sum(y * self.loss.gradient(y, y_pred), axis=0) hessian = np.sum(self.loss.hess(y, y_pred), axis=0) update_approximation = gradient / hessian
return update_approximation
# 樹擬合方法 def fit(self, X, y): self._impurity_calculation = self._gain_by_taylor self._leaf_value_calculation = self._approximate_update super(XGBoostTree, self).fit(X, y)

class XGBoost(object):
def __init__(self, n_estimators=200, learning_rate=0.001, min_samples_split=2, min_impurity=1e-7, max_depth=2): self.n_estimators = n_estimators # Number of trees self.learning_rate = learning_rate # Step size for weight update self.min_samples_split = min_samples_split # The minimum n of sampels to justify split self.min_impurity = min_impurity # Minimum variance reduction to continue self.max_depth = max_depth # Maximum depth for tree

# 交叉熵損失 self.loss = LogisticLoss()
# 初始化模型 self.estimators = [] # 前向分步訓練 for _ in range(n_estimators): tree = XGBoostTree( min_samples_split=self.min_samples_split, min_impurity=min_impurity, max_depth=self.max_depth, loss=self.loss)
self.estimators.append(tree)
def fit(self, X, y): y = to_categorical(y)
y_pred = np.zeros(np.shape(y))        for i in range(self.n_estimators): tree = self.trees[i] y_and_pred = np.concatenate((y, y_pred), axis=1) tree.fit(X, y_and_pred)            update_pred = tree.predict(X) y_pred -= np.multiply(self.learning_rate, update_pred)
def predict(self, X): y_pred = None # 預測 for tree in self.estimators: update_pred = tree.predict(X) if y_pred is None: y_pred = np.zeros_like(update_pred) y_pred -= np.multiply(self.learning_rate, update_pred)
y_pred = np.exp(y_pred) / np.sum(np.exp(y_pred), axis=1, keepdims=True) # 將概率預測轉換為標籤 y_pred = np.argmax(y_pred, axis=1) return y_pred

from sklearn import datasetsdata = datasets.load_iris()X = data.datay = data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, seed=2)  
clf = XGBoost()clf.fit(X_train, y_train)y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)print ("Accuracy:", accuracy)

Accuracy: 0.9666666666666667


XGBoost也提供了原生的模型庫可供我們調用。pip安裝xgboost即可:
import xgboost as xgbfrom xgboost import plot_importancefrom matplotlib import pyplot as plt
# 設置模型參數params = { 'booster': 'gbtree', 'objective': 'multi:softmax', 'num_class': 3, 'gamma': 0.1, 'max_depth': 2, 'lambda': 2, 'subsample': 0.7, 'colsample_bytree': 0.7, 'min_child_weight': 3, 'silent': 1, 'eta': 0.001, 'seed': 1000, 'nthread': 4,}
plst = params.items()
dtrain = xgb.DMatrix(X_train, y_train)num_rounds = 200model = xgb.train(plst, dtrain, num_rounds)
# 對測試集進行預測dtest = xgb.DMatrix(X_test)y_pred = model.predict(dtest)
# 計算準確率accuracy = accuracy_score(y_test, y_pred)print ("Accuracy:", accuracy)# 繪製特徵重要性plot_importance(model)plt.show();

Accuracy: 0.9166666666666666

參考資料:

XGBoost: A Scalable Tree Boosting System

https://www.jianshu.com/p/ac1c12f3fba1

算法工程師必備

AI有道年度技術文章電子版PDF來啦!

掃描下方二維碼,添加 AI有道小助手微信,可申請入群,並獲得2020完整技術文章合集PDF(一定要備註:入群 + 地點 + 學校/公司。例如:入群+上海+復旦。 

長按掃碼,申請入群

(添加人數較多,請耐心等待)

 

最新 AI 乾貨,我在看 

相關焦點

  • 數學推導+純Python實現機器學習算法17:XGBoost
    要深入理解整個XGBoost模型系統,建議還是要認真研讀陳天奇的 XGBoost: A Scalable Tree Boosting System 論文,深入損失函數的推導,這樣才能更好的掌握XGBoost。本文僅對模型最重要的部分,即XGBoost損失函數的數學推導過程和結點分裂的增益計算方式進行闡述。
  • 數學推導+純Python實現機器學習算法30:系列總結與感悟
    實現機器學習算法3:k近鄰數學推導+純Python實現機器學習算法4:決策樹之ID3算法數學推導+純Python實現機器學習算法5:決策樹之CART算法數學推導+純Python實現機器學習算法6:感知機數學推導+純Python實現機器學習算法7:神經網絡數學推導+純Python實現機器學習算法
  • 基於Python實現XGBoost
    XGBoost是一個優化的分布式梯度增強庫,旨在實現高效,靈活和便攜。它在Gradient Boosting框架下實現機器學習算法。XGBoost提供並行樹提升(也稱為GBDT,GBM),可以快速準確地解決許多數據科學問題。
  • Python XGBoost算法代碼實現和篩選特徵應用
    二、相比較GBDT優勢1.傳統GBDT以CART作為基分類器,xgboost還支持線性分類器,這個時候xgboost相當於帶L1和L2正則化項的邏輯斯蒂回歸(分類問題)或者線性回歸(回歸問題)。 順便提一下,xgboost工具支持自定義代價函數,只要函數可一階和二階求導。 —對損失函數做了改進(泰勒展開,一階信息g和二階信息h,上一章節有做介紹)3.xgboost在代價函數裡加入了正則項,用於控制模型的複雜度。正則項裡包含了樹的葉子節點個數、每個葉子節點上輸出的score的L2模的平方和。
  • 【機器學習】XGBoost算法學習小結
    XGBoost概述    xgboost 是"極端梯度上升"(Extreme Gradient Boosting)的簡稱,是一種現在在數據科學競賽的獲勝方案很流行的算法,它的流行源於在著名的Kaggle數據科學競賽上被稱為"奧託分類"的挑戰。由於
  • 數學推導+純Python實現機器學習算法12:貝葉斯網絡
    下面我們直接來用pgmpy實現上述貝葉斯網絡。https://github.com/luwill/machine-learning-code-writing參考資料:pgmpy: Probabilistic Graphical Models using Python數據挖掘導論往期精彩:數學推導
  • 【機器學習基礎】xgboost系列丨xgboost建樹過程分析及代碼實現
    前面我們通過對論文中的公式詳細解讀,一步步推導了XGBoost的優化目標以及建樹方法。下面我們就來動手實踐,拿真實的數據來手動計算,並且使用python來實現一個簡易的XGBoost。XGBoost的建樹過程包括下面幾個關鍵步驟。
  • 從零解讀 Xgboost 算法 (原理+代碼)
    目標函數1.2 泰勒公式對目標函數近似展開1.3 樹的參數化1.4尋找樹的形狀-特徵分裂2.工程實現細節2.0 特徵分裂並行尋找2.1 緩存訪問2.2 xgboost特徵的重要性是如何評估的3.代碼匯總3.0 xgboost 如何篩選特徵重要程度3.1 xgboost完整訓練代碼xgboost 代碼調參xgboost常規面試題參考連結0.提升樹 首先要明確一點,xgboost 是基於提升樹的。
  • 資源 | XGBoost 中文文檔開放:上去就是一把梭
    中文文檔地址:http://xgboost.apachecn.org/cn/latest/英文文檔地址:http://xgboost.apachecn.org/en/latest/中文文檔 GitHub 地址:https://github.com/apachecn/xgboost-doc-zh梯度提升樹已經在實踐中證明可以有效地用於分類和回歸任務的預測挖掘
  • 【機器學習基礎】數學推導+純Python實現機器學習算法21:馬爾可夫鏈蒙特卡洛
    19:PCA降維數學推導+純Python實現機器學習算法18:奇異值分解SVD數學推導+純Python實現機器學習算法17:XGBoost數學推導+純Python實現機器學習算法16:Adaboost>數學推導+純Python實現機器學習算法15:GBDT數學推導+純Python實現機器學習算法14:Ridge嶺回歸數學推導+純Python實現機器學習算法13:Lasso回歸
  • 資料|陳天奇介紹Xgboost原理的PPT
    from=leiphonecolumn_res0929【 圖片來源:https://xgboost.apachecn.org/所有者:https://xgboost.apachecn.org/ 】內容簡介陳天奇介紹Xgboost原理的PPT,用於學習xgboost原理。XGBoost是一個優化的分布式梯度增強庫,旨在實現高效,靈活和便攜。
  • 第113天: Python XGBoost 算法項目實戰
    XGBoost高效地實現了GBDT算法並進行了算法和工程上的許多改進,被廣泛應用在Kaggle競賽及其他許多機器學習競賽中並取得了不錯的成績。這一篇最適合剛剛接觸XGBoost的人閱讀,通過一個實戰項目拆解整個XGBoost算法。
  • 100天搞定機器學習|Day61 手算+可視化,終於徹底理解了 XGBoost
    我們已經學習了XGBoost淵源及優點、模型原理及優化推導、模型參數解析:100天搞定機器學習|Day60 遇事不決,XGBoost,文章有點太枯燥,大家可能對其中的公式推導和參數還不甚理解。#本文用到的庫import numpy as npimport pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn import preprocessingfrom xgboost.sklearn
  • 【機器學習基礎】數學推導+純Python實現機器學習算法12:貝葉斯網絡
    基於pgmpy的貝葉斯網絡實現     本節我們基於pgmpy來構造貝葉斯網絡和進行建模訓練。pgmpy是一款基於Python的概率圖模型包,主要包括貝葉斯網絡和馬爾可夫蒙特卡洛等常見概率圖模型的實現以及推斷方法。本節使用pgmpy包來實現簡單的貝葉斯網絡。
  • Python-SHAP的實現
    利用SHAP解釋Xgboost模型-SofaSofahttp://sofasofa.io/tutorials/shap_xgboost/模型解釋–SHAP Value的簡單介紹 - 簡書https://www.jianshu.com/p/6c40fbf1fadb
  • 數學推導+純Python實現機器學習算法20:隨機森林
    Bagging與Boosting圖示如下:    可以清楚的看到,Bagging是並行的框架,而Boosting則是序列框架(但也可以實現並行)。    有了之前多篇關於決策樹的基礎以及前述關於Bagging基本思想的闡述,隨機森林(Random Forest)就沒有太多難以理解的地方了。
  • 數學推導+純Python實現機器學習算法28:奇異值分解SVD
    Python機器學習算法實現Author:louwillMachine
  • python金融風控評分卡模型和數據分析
    這套微專業課程是網際網路上最全,最專業的python信貸建模教程。針對銀行,消費金融的現金貸等線上貸款場景,金融信貸領域建模型和數據分析很難?邏輯回歸評分卡/catboost/xgboost/lightgbm/等模型用python一次全部搞定!由易到難,帶你從菜鳥輕鬆晉級kaggle級建模高手。
  • 我的XGBoost學習經歷及動手實踐
    XGBoost是一個優化的分布式梯度增強庫,旨在實現高效,靈活和便攜。它在Gradient Boosting框架下實現機器學習算法。XGBoost提供了並行樹提升(也稱為GBDT,GBM),可以快速準確地解決許多數據科學問題。相同的代碼在主要的分布式環境(Hadoop,SGE,MPI)上運行,並且可以解決超過數十億個樣例的問題。
  • 機器學習實戰|GBDT Xgboost LightGBM對比
    import xgboost as xgbimport numpy as npimport time# read data into Xgboost DMatrix formatdtrain = xgb.DMatrix(Xtrain