Xgboost算法原理详解及python实现
Xgboost算法(回歸樹)
- 1、算法原理
- 2、對數據的要求(無需規范化)
- 3、算法的優缺點
- 4、XGB、GBDT、LR與RF
- 5、python代碼實現
- 導入相關包
- 讀取數據并預處理
- 訓練
- 貝葉斯初步優化
- 網格搜索調參(一般調參順序)
1、算法原理
步驟(booststrap sampling):
目標函數:obj(t)=∑i=1nL(yi,y^i(t?1)+ftxi)+Ωf(t)+Cobj^{(t)}=\sum_{i=1}^nL(y_i,\widehat y_i^{(t-1)}+f_t^{x_i})+\Omega f(t)+Cobj(t)=∑i=1n?L(yi?,y?i(t?1)?+ftxi??)+Ωf(t)+C
Taylor展開:f(x+Δx)≈f(x)+f′(x)Δx+12f′′(x)(Δx)2f(x+\Delta x)\approx f(x)+f'(x)\Delta x+\frac{1}{2}f''(x)(\Delta x)^2f(x+Δx)≈f(x)+f′(x)Δx+21?f′′(x)(Δx)2
加法訓練優化步驟:
{y^i(0)=0y^i(1)=f1(xi)=y^i(0)+f1(xi)......y^i(t)=∑k=1tfk(xi)=y^i(t?1)+ft(xi)\begin{cases} \widehat y_i^{(0)}=0\\ \widehat y_i^{(1)}=f_1(x_i)=\widehat y_i^{(0)}+f_1(x_i)\\ ......\\ \widehat y_i^{(t)}=\sum_{k=1}^tf_k(x_i)=\widehat y_i^{(t-1)}+f_t(x_i) \end{cases}??????????y?i(0)?=0y?i(1)?=f1?(xi?)=y?i(0)?+f1?(xi?)......y?i(t)?=∑k=1t?fk?(xi?)=y?i(t?1)?+ft?(xi?)?
目標函數進一步可表示為:
obj(t)=∑i=1nl(yi,y^i(t))+∑i=1tΩf(t)obj^{(t)}=\sum_{i=1}^nl(y_i,\widehat y_i^{(t)})+\sum_{i=1}^t\Omega f(t)obj(t)=∑i=1n?l(yi?,y?i(t)?)+∑i=1t?Ωf(t)
∑i=1tΩf(t)=Ωf(t)+∑i=1t?1Ωf(t?1)=Ωf(t)+constatnt\sum_{i=1}^t\Omega f(t)=\Omega f(t)+\sum_{i=1}^{t-1}\Omega f(t-1)=\Omega f(t)+constatnt∑i=1t?Ωf(t)=Ωf(t)+∑i=1t?1?Ωf(t?1)=Ωf(t)+constatnt 其中∑i=1t?1Ωf(t?1)/constant\sum_{i=1}^{t-1}\Omega f(t-1)/constant∑i=1t?1?Ωf(t?1)/constant表示前t-1棵樹的復雜度
obj(t)=∑i=1nl(yi,y^i(t?1)+f(t)(xi))+Ωf(t)+constantobj^{(t)}=\sum_{i=1}^nl(y_i,\widehat y_i^{(t-1)}+f_{(t)}(x_i))+\Omega f(t)+constantobj(t)=∑i=1n?l(yi?,y?i(t?1)?+f(t)?(xi?))+Ωf(t)+constant
y^i(t)=y^i(t?1)+f(t)(xi)\widehat y_i^{(t)}=\widehat y_i^{(t-1)}+f_{(t)}(x_i)y?i(t)?=y?i(t?1)?+f(t)?(xi?) 其中f(t)(xi)f_{(t)}(x_i)f(t)?(xi?)是第t課樹,是唯一一個需要學習的變量,其余都為已知量。Ωf(t)\Omega f(t)Ωf(t)是第t棵樹的復雜度。constantconstantconstant前t?1t-1t?1棵樹的復雜度
obj(t)=∑i=1n[l(yi,y^i(t?1))+gift(xi)+12hift2(xi)]+Ωf(t)+constantobj^{(t)}=\sum_{i=1}^n[l(y_i,\widehat y_i^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_t^2(x_i)]+\Omega f(t)+constantobj(t)=∑i=1n?[l(yi?,y?i(t?1)?)+gi?ft?(xi?)+21?hi?ft2?(xi?)]+Ωf(t)+constant
其中gig_igi?和hih_ihi?定義如下:
{gi=?y^(t?1)l(yi,y^(t?1))hi=?2y^(t?1)l(yi,y^(t?1))\begin{cases} g_i=\partial\widehat y^{(t-1)}l(y_i,\widehat y^{(t-1)})\\ h_i=\partial^2\widehat y^{(t-1)}l(y_i,\widehat y^{(t-1)}) \end{cases}{gi?=?y?(t?1)l(yi?,y?(t?1))hi?=?2y?(t?1)l(yi?,y?(t?1))?
1、定義樹的復雜度Ωf(t)=γT+12λ∑j=1Twj2\Omega f(t)=\gamma T+\frac{1}{2}\lambda\sum_{j=1}^{T}w_j^2Ωf(t)=γT+21?λ∑j=1T?wj2? 其中TTT為葉子節點數量;λ\lambdaλ為一個葉子帶來的復雜度;wj2w_j^2wj2?為葉子節點L2L_2L2?的范數;jjj為葉子節點數量
2、定義一棵樹:ft(x)=Wq(x)(w∈RT,q:Rd→{1、2.....T})f_t(x)=W_{q(x)}(w \in R^T,q:R^d\rightarrow\{1、2.....T\})ft?(x)=Wq(x)?(w∈RT,q:Rd→{1、2.....T}) 其中www為一維向量,代表樹qqq各個葉子節點權重;qqq代表一棵樹的結構
去常數項 :
obj(t)=∑i=1n[gift(xi)+12hift2(xi)]+Ωf(t)=∑i=1n[giwq(xi)+12hiwq(xi)2]+γT+12λ∑j=1Twj2=∑j=1T[(∑i∈Ijgi)wj+12(∑i∈Ijhi+λ)wj2]+γT\begin{aligned} obj^{(t)}&=\sum_{i=1}^n[g_if_t(x_i)+\frac{1}{2}h_if_t^2(x_i)]+\Omega f(t)\\ &=\sum_{i=1}^n[g_iw_{q(x_i)}+\frac{1}{2}h_iw_{q(x_i)}^2]+\gamma T+\frac{1}{2}\lambda\sum_{j=1}^{T}w_j^2\\ &=\sum_{j=1}^T[(\sum_{i \in I_j}g_i)w_j+\frac{1}{2}(\sum_{i \in I_j}h_i+\lambda)w_j^2]+\gamma T \end{aligned} obj(t)?=i=1∑n?[gi?ft?(xi?)+21?hi?ft2?(xi?)]+Ωf(t)=i=1∑n?[gi?wq(xi?)?+21?hi?wq(xi?)2?]+γT+21?λj=1∑T?wj2?=j=1∑T?[(i∈Ij?∑?gi?)wj?+21?(i∈Ij?∑?hi?+λ)wj2?]+γT?
∑j=1T\sum_{j=1}^T∑j=1T?將所有訓練樣本,按葉子節點進行了分組。其中Ij={i∣q(xi)=j}將屬于第I_j=\{i|q(x_i)=j\}將屬于第Ij?={i∣q(xi?)=j}將屬于第j個葉子節點所有樣本個葉子節點所有樣本個葉子節點所有樣本x_i$,劃入到一個葉子節點樣本集中
obj(t)=∑j=1T[Gjwj+12(Hj+λ)wj2]+γTobj^{(t)}=\sum_{j=1}^T[G_jw_j+\frac{1}{2}(H_j+\lambda)w_j^2]+\gamma Tobj(t)=∑j=1T?[Gj?wj?+21?(Hj?+λ)wj2?]+γT
Gj=∑i∈IjgiG_j=\sum_{i \in I_j}g_iGj?=∑i∈Ij??gi?:葉子節點jjj所包含樣本一階偏導數累加之和(常量);Hj=∑i∈IjhiH_j=\sum_{i \in I_j}h_iHj?=∑i∈Ij??hi?:葉子節點jjj所包含樣本二階偏導數累加之和(常量)
求解:
{wj?=?GjHj+λ(每個葉子節點權重score)obj=?12∑j=1TGj2Hj+λ+γT(第t棵樹帶來的最小損失)\begin{cases} w_j^*=-\frac{G_j}{H_j+\lambda} (每個葉子節點權重score)\\ obj=-\frac{1}{2}\sum_{j=1}^T\frac{G_j^2}{H_j+\lambda}+\gamma T(第t棵樹帶來的最小損失) \end{cases}{wj??=?Hj?+λGj??(每個葉子節點權重score)obj=?21?∑j=1T?Hj?+λGj2??+γT(第t棵樹帶來的最小損失)?
分裂指標(分割點在Gain最大且大于0):
Gain=objL+R?(objL+objR)=[?12(GL+GR)2HL+HR+λ+γ]?[?12(GL)2HL+λ+(GR)2HR+λ+2λ]\begin{aligned} Gain&=obj_{L+R}-(obj_{L}+obj_{R})\\ &=[-\frac{1}{2}\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}+\gamma]-[-\frac{1}{2}\frac{(G_L)^2}{H_L+\lambda}+\frac{(G_R)^2}{H_R+\lambda}+2\lambda] \end{aligned}Gain?=objL+R??(objL?+objR?)=[?21?HL?+HR?+λ(GL?+GR?)2?+γ]?[?21?HL?+λ(GL?)2?+HR?+λ(GR?)2?+2λ]?
Gain>0則obj下降了;Gain<0分裂失敗
2、對數據的要求(無需規范化)
不需要歸一化,能自動處理缺失值
3、算法的優缺點
一、優點:
- 許多策略防止過擬合(正則化、Shrinkage、樣本抽樣與列抽樣)
- 目標函數利用了二階導數(1、增加精度;2、能夠自定義損失函數。二階泰勒展開可以近似大量損失函數)
- 支持并行化
- 支持設置樣本權重,該權重體現在一階導數g和二階導數h通過調整權重可以去關注一些樣本
- 添加了對稀疏數據處理(缺失值處理)
- 精度高
二、缺點:
- 雖然利用了預排序和近似算法能降低尋找最佳分割點的計算量,但在節點分裂過程中仍需要遍歷數據集
- 預排序消耗兩倍內存
4、XGB、GBDT、LR與RF
XGB與GBDT的不同之處
1、XGB在目標函數中加了正則化項(相當于預剪枝,不易過擬合)
2、XGB不僅用了一階導數而且還使用了二階導數
3、支持并行化
4、XGB的基分類器除了CART還可以是線性分類器
5、缺失值處理,自動學習出他的默認分裂方向
6、支持列抽樣
XGB為什么使用泰勒二階展開
1、精準性:更為精準的逼近真實的損失函數
2、可擴展性:損失函數支持自定義,只需要新的損失函數二階可導
XGB為什么可以并行訓練
特征維度并行:在訓練之前,每個特征按特征值進行預排序,并存儲Block結構,在后面查找分割點重復使用(并行查找)
XGB為什么快
1、分塊并行:訓練前每個特征值排序并存儲Block結構,后面查找分割點重復使用,支持并行查找每個特征分割點
2、候選分割點:每個特征采用常數個分位點作為候選分割點
3、CPU cache命中優化:使用緩存預取的方法,對每個線性分配一個連續buffer,讀取每個Block中樣本的梯度信息并存入連續buffer中
4、Block處理優化:Block預先放入內存,Block按列進行解壓縮,將Block劃分到不同硬盤來提高吞吐
XGB防止過擬合的方法
1、目標函數添加了正則項(葉子節點數+葉子節點權重L2L_2L2?正則化)
2、列抽樣(訓練的時候只用一部分特征)
3、子采樣(每輪計算可以不使用全部樣本)
4、Shrinkage(學習率|步長,為了給后面訓練流出更多的學習空間)
XGB如何處理缺失值
1、在特征上尋找分割點時不考慮缺失值,只考慮non—missing值
2、訓練時缺失值自定義劃分方向放到右子結點
3、預測時分別劃分到左葉子節點與右葉子節點各計算一遍,選擇分裂后增益最大的方向
XGB一棵樹停止生長的條件
1、Gain<0停止分裂
2、達到樹的最大深度
3、最小樣本權重和(引入一次分裂后,重新計算生成左右2個葉子結點的樣本權重和,如果任意一個葉子節點的樣本權重低于某一個閾值,放棄本次分裂)
4、最小樣本數量(葉子)
XGB如何處理不平衡數據
1、采用AUC評估模型性能,可以通過scale_pos_weight來平衡正、負樣本權重(關注AUC)
2、通過上采樣與下采樣
3、如果在意正確率,不能平衡數據(破壞真實分布),應該設置max_delta_step為一個有限數字幫助收斂(基模型為LR時有效)
GBDT與LR
1、LR可解釋性強,可并行化,需要大量特征工程
2、GBDT非線性,特征表達能力強,無法并行,易過擬合
3、高維稀疏場景下,LR比GBDT好
XGB如何剪枝
1、正則化
2、Gain的閾值
3、最小樣本權重和
4、最大深度
XGB如何評價特征重要性
1、weight:該特征在所有樹中被用作分割樣本特征的總次數
2、gain:該特征在其出現過的所有樹中產生平均增益
3、cover:在其出現過的所有樹中平均覆蓋范圍(一個特征作為分割點,影響的樣本數量。即有多少個樣本經過該特征分割到2個子節點)
XGB過擬合如何解決
1、控制模型復雜度(max_depth、min_child_weight等參數)
2、增加隨機性(subsample和colsample_bytree)
3、減少學習率,同時增加迭代次數(estimator)
RF與GBDT的區別
1、集成學習:RF屬于baggig,GBDT屬于boosting
2、偏差-方差:RF降低方差,GBDT降低偏差
3、訓練樣本:RF抽樣,GBDT全部樣本
4、并行:RF可并行,GBDT不可并行
5、泛化能力:RF不易過擬合,GBDT易過擬合
6、異常值:RF對異常值不敏感,GBDT對異常值敏感
5、python代碼實現
導入相關包
import numpy as np import pandas as pd from sklearn.preprocessing import LabelEncoder#分類變量編碼包 from sklearn.metrics import roc_auc_score,roc_curve,auc,precision_score,f1_score,accuracy_score,classification_report,recall_score from sklearn.model_selection import train_test_split from xgboost.sklearn import XGBClassifier import matplotlib.pylab as plt import xgboost as xgbimport os os.chdir('E:/wyz/Desktop/XGB/')讀取數據并預處理
data = pd.read_excel('ceshi.xlsx',sheet_name = 'Sheet2') #分類變量編碼 from sklearn.preprocessing import LabelEncoder le = LabelEncoder() str_variable = list(data.dtypes[data.dtypes.values == object].index) for col in str_variable: data[col] = le.fit_transform(data[col].astype(str)) #劃分數據集 y = data_model['target'] x = data_model.drop('target', axis=1) x_train, x_test, y_train, y_test = train_test_split(x, y,random_state=0,train_size=0.7)訓練
#通過交叉驗證的方法來獲取最優的迭代次數(樹的數量) def modelfit1(alg,train_x,train_y,test_x,test_y,useTrainCV=True,cv_folds=5,early_stopping_rounds=20):if useTrainCV:xgb_param = alg.get_xgb_params()#獲取xgb參數xgtrain = xgb.DMatrix(train_x.values,label=train_y.values)#傳入x和ycvresult = xgb.cv(xgb_param,xgtrain,#訓練數據num_boost_round=alg.get_params()['n_estimators'],#樹的數量nfold=cv_folds,#交叉驗證metrics='auc',#評價指標early_stopping_rounds=early_stopping_rounds,#連續迭代多少次auc不在下降 # verbose_eval=10,#每隔1輪打印一次評價指標show_stdv=False )#不打印標準差alg.set_params(n_estimators=cvresult.shape[0])#得到最優的樹的數量#訓練集上的擬合alg.fit(train_x,train_y,eval_metric='auc')#傳入x和y#訓練集上的預測train_class = alg.predict(train_x)#輸出0和1train_prob = alg.predict_proba(train_x)[:,1]#輸出1的概率#測試集上的預測test_class = alg.predict(test_x)#輸出0和1test_prob = alg.predict_proba(test_x)[:,1]#輸出1的概率#準確率與aucprint('訓練集準確率: %.4f'%accuracy_score(train_y,train_class))##準確率,預測為類別(normalize=False返回預測正確的個數)print('測試集準確率: %.4f'%accuracy_score(test_y,test_class))#準確率,預測為類別(normalize=False返回預測正確的個數)print('訓練集AUC: %.4f'%roc_auc_score(train_y,train_prob))#AUC,預測為概率print('測試集AUC: %.4f'%roc_auc_score(test_y,test_prob))#AUC,預測為概率#print(alg.feature_importances_)#變量重要性return alg貝葉斯初步優化
#預測結果 from sklearn.model_selection import cross_val_score from bayes_opt import BayesianOptimization #定義貝葉斯優化的f def model_target(learning_rate,n_estimators,max_depth,min_child_weight,subsample,colsample_bytree,reg_alpha,gamma):val = cross_val_score(XGBClassifier(learning_rate =learning_rate,#學習率n_estimators=int(n_estimators),#最多的樹的數量max_depth=int(max_depth),#每棵樹的最大深度min_child_weight=min_child_weight,#葉子節點最小的樣本權重和subsample=subsample,#行抽樣colsample_bytree=colsample_bytree,#列抽樣objective= 'binary:logistic',reg_alpha=reg_alpha,#正則化gamma=gamma,#當損失函數減少時才會分裂scale_pos_weight=1,#數值大于0,在樣本的類非常不均衡時使用有助于快速收斂seed=27),x_train,y_train,scoring='roc_auc',cv=5).mean()return val model_bo = BayesianOptimization(model_target,{'learning_rate':(0.01,0.01),'n_estimators': (100, 1000),'max_depth': (2, 4),'min_child_weight': (0,1),'subsample': (0.6, 1),'colsample_bytree':(0.6,1),'reg_alpha': (0.001, 10),'gamma':(0.0,0.0)}) model_bo.maximize()貝葉斯進階優化
#預測結果 from sklearn.model_selection import cross_val_score from bayes_opt import BayesianOptimization #定義貝葉斯優化的f def model_target(learning_rate,n_estimators,max_depth,min_child_weight,subsample,colsample_bytree,reg_alpha,gamma):val = cross_val_score(XGBClassifier(learning_rate =learning_rate,#學習率n_estimators=int(n_estimators),#最多的樹的數量max_depth=int(max_depth),#每棵樹的最大深度min_child_weight=min_child_weight,#葉子節點最小的樣本權重和subsample=subsample,#行抽樣colsample_bytree=colsample_bytree,#列抽樣objective= 'binary:logistic',reg_alpha=reg_alpha,#正則化gamma=gamma,#當損失函數減少時才會分裂scale_pos_weight=1,#數值大于0,在樣本的類非常不均衡時使用有助于快速收斂seed=27),x_train,y_train,scoring='roc_auc',cv=5).mean()return val model_bo = BayesianOptimization(model_target,{'learning_rate':(0.01,0.01),'n_estimators': (100, 1000),'max_depth': (2, 4),'min_child_weight': (0,1),'subsample': (0.6, 1),'colsample_bytree':(0.6,1),'reg_alpha': (0.001, 10),'gamma':(0.0,0.0)}) model_bo.maximize()網格搜索調參(一般調參順序)
- 尋找最優的樹深度與最優的樣本權重和
- 尋找最優gamma值
- 尋找subsample和colsample_bytree值
- reg_alpha正則化
- 降低學習率獲取,增加更多的樹
XGB參數詳解
| booster | 默認值:gbtree 輸入:gbtree、gblinear | 在每次迭代中選擇模型的類型,有2個選項:gbtree:基于樹的模型gblinear:基于回歸的模型 |
| silent | 默認值:0 輸入:0、1 | 激活Silent mode就設置為1,即正在運行的消息不會被打印。默認為0,好處就是幫助我們理解模型運行狀況 |
| nthread | 默認值:使用所有的核 | 這個參數用于并行處理,系統中的核的數量如果想運行所有的核,就不用再輸入nthread的值,因為默認情況就是使用所有核。還有另外兩個參數是由XGBoost自動設置的,下面繼續探索Booster參數 |
| eta | 默認值:0.3 | 與GBM中的eta類似。在每一步中收縮權重使得模型更加穩健。通常設置值為:0.01?0.2 |
| min_child_weight | 默認值:1 | 孩子節點中最小的樣本權重和。如果一個葉子節點的樣本權重和小于min_child_weight則拆分過程結束。在現行回歸模型中,這個參數是指建立每個模型所需要的最小樣本數。該成熟越大算法越conservative這與GBM中的min_child_leaf類似,但不完全相同,XGBoost指 min “sum of weights” of observations 而 GBM 為 min “number of observations”。可用于控制過擬合。太高的值可能導致欠擬合,應使用CV進行調參 |
| max_depth | 默認值:6 | 與GBM一樣,定義了一棵樹的最大深度。用于控制過擬合,因為較高的深度會使模型對一些樣本學習到特定關系,而這種關系又不是泛化的。適合用CV進行調整值的大小。通常設置值為:3?10 |
| max_leaf_nodes | 樹中節點或樹葉的最大數量。有時可以代替max_depth。 如:二叉樹,深度“n”將產生最大2 ^ n個葉。如果這樣,GBM可以忽略max_depth | |
| gamma | 默認值:0 | 只有當損失函數以正值減少時,節點才會分割。 Gamma指定了進行分割時所需的最小損失的減少量。使算法比較保守。 Gamma值可以根據損失函數調整大小 |
| max_delta_step | 默認值:0 | 如果max_delta_step設置為0,表示沒有約束。 可以取正值。這個參數不是必須要設定的。在邏輯回歸中,當類別比例非常不平衡時,這個參數很有用 |
| subsample | 默認值:1 | 與GBM取子樣本一樣,都是對總體進行隨機采樣出子樣本占總體的比例。較低的值使算法比較保守,可以防止過度擬合,但太小的值可能會導致欠擬合。通常設置值為:0.5?1 |
| colsample_bytree | 默認值:1 | 類似于GBM中的max_features。 表示隨機抽取的列數占總列數的比例。通常設置值為:0.5?1 |
| colsample_bylevel | 默認值:1 | 表示每個層中用于拆分時的列數占比(相當于選出的列數的再比例)。這個參數不常用,因為subsample和 colsample_bytree可以替代這個參數的作用 |
| lambda | 默認值:1 | L2對權重正則化(Ridge回歸也是L2)這用于XGBoost的正則化部分。 雖然許多數據科學家一般不用它,但是減少過擬合的時候還是要用一下的 |
| alpha | 默認值:0 | L1對權重正則化(類似于Lasso回歸的L1)維度較高時使用,可以運行得更快 |
| scale_pos_weight | 默認值:1 | 數值大于0,在樣本的類非常不均衡時使用有助于快速收斂 |
| seed | 默認值:0 | 種子隨機數。使采樣的結果與之前相同以及參數調整 |
| objective | 默認值:reg:linear | 這個參數定義了要最小化的損失函數。 有如下選擇: objective [default=reg:linear] 這個參數定義了要最小化的損失函數。 有如下選擇: binary:logistic:用于二分類的邏輯回歸,返回值為概率,非類別。 multi:softmax:使用softmax目標的多類分類返回預測類(不是概率)。 還需設置一個num_class(number of classes)參數來定義類的數量。 multi:softprob: 與softmax相同,但返回的是每個樣本屬于每個類的預測概率而不是類別。 eval_metric [ default according to objective ] 默認值為rmse用于回歸,錯誤率用于分類。可選值有: 1、rmse – root mean square error 2、mae – mean absolute error 3、logloss– negative log-likelihood 4、error – Binary classification error rate (0.5 threshold) 5、merror – Multiclass classification error rate 6、mlogloss – Multiclass logloss 7、auc: Area under the curve |
總結
以上是生活随笔為你收集整理的Xgboost算法原理详解及python实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 随机森林原理详解及python代码实现
- 下一篇: 朴素贝叶斯算法详解及python代码实现