XGBoost類庫使用小結


    在XGBoost算法原理小結中,我們討論了XGBoost的算法原理,這一片我們討論如何使用XGBoost的Python類庫,以及一些重要參數的意義和調參思路。

    本文主要參考了XGBoost的Python文檔 和 XGBoost的參數文檔

1. XGBoost類庫概述

    XGBoost除了支持Python外,也支持R,Java等語言。本文關注於Python的XGBoost類庫,安裝使用"pip install xgboost"即可,目前使用的是XGBoost的0.90版本。XGBoost類庫除了支持決策樹作為弱學習器外,還支持線性分類器,以及帶DropOut的決策樹DART,不過通常情況下,我們使用默認的決策樹弱學習器即可,本文也只會討論使用默認決策樹弱學習器的XGBoost。

    XGBoost有2種Python接口風格。一種是XGBoost自帶的原生Python API接口,另一種是sklearn風格的API接口,兩者的實現是基本一樣的,僅僅有細微的API使用的不同,主要體現在參數命名上,以及數據集的初始化上面。

2. XGBoost類庫的基本使用方式

    完整示例參見我的Github代碼

2.1 使用原生Python API接口

    XGBoost的類庫的2種接口風格,我們先來看看原生Python API接口如何使用。

    原生XGBoost需要先把數據集按輸入特征部分,輸出部分分開,然后放到一個DMatrix數據結構里面,這個DMatrix我們不需要關心里面的細節,使用我們的訓練集X和y初始化即可。

import pandas as pd
import numpy as np
import xgboost as xgb
import matplotlib.pylab as plt
%matplotlib inline

from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.datasets.samples_generator import make_classification
# X為樣本特征,y為樣本類別輸出, 共10000個樣本,每個樣本20個特征,輸出有2個類別,沒有冗余特征,每個類別一個簇
X, y = make_classification(n_samples=10000, n_features=20, n_redundant=0,
                             n_clusters_per_class=1, n_classes=2, flip_y=0.1)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
dtrain = xgb.DMatrix(X_train,y_train)
dtest = xgb.DMatrix(X_test,y_test)

    上面的代碼中,我們隨機初始化了一個二分類的數據集,然后分成了訓練集和驗證集。使用訓練集和驗證集分別初始化了一個DMatrix,有了DMatrix,就可以做訓練和預測了。簡單的示例代碼如下:

param = {'max_depth':5, 'eta':0.5, 'verbosity':1, 'objective':'binary:logistic'}
raw_model = xgb.train(param, dtrain, num_boost_round=20)
from sklearn.metrics import accuracy_score
pred_train_raw = raw_model.predict(dtrain)
for i in range(len(pred_train_raw)):
    if pred_train_raw[i] > 0.5:
         pred_train_raw[i]=1
    else:
        pred_train_raw[i]=0               
print (accuracy_score(dtrain.get_label(), pred_train_raw))

    訓練集的准確率我這里輸出是0.9664。再看看驗證集的表現:

pred_test_raw = raw_model.predict(dtest)
for i in range(len(pred_test_raw)):
    if pred_test_raw[i] > 0.5:
         pred_test_raw[i]=1
    else:
        pred_test_raw[i]=0               
print (accuracy_score(dtest.get_label(), pred_test_raw))

    驗證集的准確率我這里的輸出是0.9408,已經很高了。

     不過對於我這樣用慣sklearn風格API的,還是不太喜歡原生Python API接口,既然有sklearn的wrapper,那么就盡量使用sklearn風格的接口吧。

2.2 使用sklearn風格接口,使用原生參數

    對於sklearn風格的接口,主要有2個類可以使用,一個是分類用的XGBClassifier,另一個是回歸用的XGBRegressor。在使用這2個類的使用,對於算法的參數輸入也有2種方式,第一種就是仍然使用和原始API一樣的參數命名集合,另一種是使用sklearn風格的參數命名。我們這里先看看如何使用和原始API一樣的參數命名集合。

    其實就是使用XGBClassifier/XGBRegressor的**kwargs參數,把上面原生參數的params集合放進去,代碼如下:

sklearn_model_raw = xgb.XGBClassifier(**param)
sklearn_model_raw.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="error",
        eval_set=[(X_test, y_test)])

    里面的param其實就是2.1節里面定義的:

param = {'max_depth':5, 'eta':0.5, 'verbosity':1, 'objective':'binary:logistic'}

    使用sklearn風格的接口,卻使用原始的參數名定義,感覺還是有點怪,所以我一般還是習慣使用另一種風格接口,sklearn風格的參數命名。

2.3 使用sklearn風格接口,使用sklearn風格參數

    使用sklearn風格的接口,並使用sklearn風格的參數,是我推薦的方式,主要是這樣做和GBDT之類的sklearn庫使用起來沒有什么兩樣了,也可以使用sklearn的網格搜索。

    不過這樣做的話,參數定義命名和2.1與2.2節就有些不同了。具體的參數意義我們后面講,我們看看分類的算法初始化,訓練與調用的簡單過程:

sklearn_model_new = xgb.XGBClassifier(max_depth=5,learning_rate= 0.5, verbosity=1, objective='binary:logistic',random_state=1)

    可以看到,參數定義直接放在了XGBClassifier的類參數里,和sklearn類似。大家可以看到之前兩節我們定義的步長eta,這里變成了另一個名字learning_rate。

    在初始化后,訓練和預測的方法就和2.2節沒有區別了。

sklearn_model_new.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="error",
        eval_set=[(X_test, y_test)])

3. XGBoost類庫參數

    在第二節我們已經嘗試使用XGBoost類庫了,但是對於XGBoost的類庫參數並沒有過多討論。這里我們就詳細討論下,主要以2.3節的sklearn風格參數為主來進行討論。這些參數我會和之前講的scikit-learn 梯度提升樹(GBDT)調參小結中的參數定義對應,這樣如果大家對GBDT的調參很熟悉了,那么XGBoost的調參也就掌握90%了。

    XGBoost的類庫參數主要包括boosting框架參數,弱學習器參數以及其他參數。

3.1  XGBoost框架參數 

    對於XGBoost的框架參數,最重要的是3個參數: booster,n_estimators和objectve。

    1) booster決定了XGBoost使用的弱學習器類型,可以是默認的gbtree, 也就是CART決策樹,還可以是線性弱學習器gblinear以及DART。一般來說,我們使用gbtree就可以了,不需要調參。

    2) n_estimators則是非常重要的要調的參數,它關系到我們XGBoost模型的復雜度,因為它代表了我們決策樹弱學習器的個數。這個參數對應sklearn GBDT的n_estimators。n_estimators太小,容易欠擬合,n_estimators太大,模型會過於復雜,一般需要調參選擇一個適中的數值。

    3) objective代表了我們要解決的問題是分類還是回歸,或其他問題,以及對應的損失函數。具體可以取的值很多,一般我們只關心在分類和回歸的時候使用的參數。

    在回歸問題objective一般使用reg:squarederror ,即MSE均方誤差。二分類問題一般使用binary:logistic, 多分類問題一般使用multi:softmax。

 3.2  XGBoost 弱學習器參數   

    這里我們只討論使用gbtree默認弱學習器的參數。  要調參的參數主要是決策樹的相關參數如下: 

    1)   max_depth: 控制樹結構的深度,數據少或者特征少的時候可以不管這個值。如果模型樣本量多,特征也多的情況下,需要限制這個最大深度,具體的取值一般要網格搜索調參。這個參數對應sklearn GBDT的max_depth。

    2) min_child_weight: 最小的子節點權重閾值,如果某個樹節點的權重小於這個閾值,則不會再分裂子樹,即這個樹節點就是葉子節點。這里樹節點的權重使用的是該節點所有樣本的二階導數的和,即XGBoost原理篇里面的$H_{tj}$:$$H_{tj} =  \sum\limits_{x_i \in R_{tj}}h_{ti}$$

    這個值需要網格搜索尋找最優值,在sklearn GBDT里面,沒有完全對應的參數,不過min_samples_split從另一個角度起到了閾值限制。

    3) gamma: XGBoost的決策樹分裂所帶來的損失減小閾值。也就是我們在嘗試樹結構分裂時,會嘗試最大數下式:$$ \max \frac{1}{2}\frac{G_L^2}{H_L + \lambda} + \frac{1}{2}\frac{G_R^2}{H_R+\lambda}  - \frac{1}{2}\frac{(G_L+G_R)^2}{H_L+H_R+ \lambda} - \gamma$$

    這個最大化后的值需要大於我們的gamma,才能繼續分裂子樹。這個值也需要網格搜索尋找最優值。

    4) subsample: 子采樣參數,這個也是不放回抽樣,和sklearn GBDT的subsample作用一樣。選擇小於1的比例可以減少方差,即防止過擬合,但是會增加樣本擬合的偏差,因此取值不能太低。初期可以取值1,如果發現過擬合后可以網格搜索調參找一個相對小一些的值。

    5) colsample_bytree/colsample_bylevel/colsample_bynode: 這三個參數都是用於特征采樣的,默認都是不做采樣,即使用所有的特征建立決策樹。colsample_bytree控制整棵樹的特征采樣比例,colsample_bylevel控制某一層的特征采樣比例,而colsample_bynode控制某一個樹節點的特征采樣比例。比如我們一共64個特征,則假設colsample_bytree,colsample_bylevel和colsample_bynode都是0.5,則某一個樹節點分裂時會隨機采樣8個特征來嘗試分裂子樹。

    6) reg_alpha/reg_lambda: 這2個是XGBoost的正則化參數。reg_alpha是L1正則化系數,reg_lambda是L2正則化系數,在原理篇里我們討論了XGBoost的正則化損失項部分:$$\Omega(h_t) = \gamma J + \frac{\lambda}{2}\sum\limits_{j=1}^Jw_{tj}^2$$

    上面這些參數都是需要調參的,不過一般先調max_depth,min_child_weight和gamma。如果發現有過擬合的情況下,再嘗試調后面幾個參數。

3.3  XGBoost 其他參數

    XGBoost還有一些其他的參數需要注意,主要是learning_rate。

    learning_rate控制每個弱學習器的權重縮減系數,和sklearn GBDT的learning_rate類似,較小的learning_rate意味着我們需要更多的弱學習器的迭代次數。通常我們用步長和迭代最大次數一起來決定算法的擬合效果。所以這兩個參數n_estimators和learning_rate要一起調參才有效果。當然也可以先固定一個learning_rate ,然后調完n_estimators,再調完其他所有參數后,最后再來調learning_rate和n_estimators。

    此外,n_jobs控制算法的並發線程數, scale_pos_weight用於類別不平衡的時候,負例和正例的比例。類似於sklearn中的class_weight。importance_type則可以查詢各個特征的重要性程度。可以選擇“gain”, “weight”, “cover”, “total_gain” 或者 “total_cover”。最后可以通過調用booster的get_score方法獲取對應的特征權重。“weight”通過特征被選中作為分裂特征的計數來計算重要性,“gain”和“total_gain”則通過分別計算特征被選中做分裂特征時帶來的平均增益和總增益來計算重要性。“cover”和 “total_cover”通過計算特征被選中做分裂時的平均樣本覆蓋度和總體樣本覆蓋度來來計算重要性。

4. XGBoost網格搜索調參

    XGBoost可以和sklearn的網格搜索類GridSeachCV結合使用來調參,使用時和普通sklearn分類回歸算法沒有區別。具體的流程的一個示例如下:

gsCv = GridSearchCV(sklearn_model_new,
                   {'max_depth': [4,5,6],
                    'n_estimators': [5,10,20]})
gsCv.fit(X_train,y_train)
print(gsCv.best_score_)
print(gsCv.best_params_)

    我這里的輸出是:

    0.9533333333333334

    {'max_depth': 4, 'n_estimators': 10}

    接着嘗試在上面搜索的基礎上調learning_rate :

sklearn_model_new2 = xgb.XGBClassifier(max_depth=4,n_estimators=10,verbosity=1, objective='binary:logistic',random_state=1)
gsCv2 = GridSearchCV(sklearn_model_new2, 
                   {'learning_rate ': [0.3,0.5,0.7]})
gsCv2.fit(X_train,y_train)
print(gsCv2.best_score_)
print(gsCv2.best_params_)

    我這里的輸出是:

    0.9516

    {'learning_rate ': 0.3}

    當然實際情況這里需要繼續調參,這里假設我們已經調參完畢,我們嘗試用驗證集看看效果:

sklearn_model_new2 = xgb.XGBClassifier(max_depth=4,learning_rate= 0.3, verbosity=1, objective='binary:logistic',n_estimators=10)
sklearn_model_new2.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="error",
        eval_set=[(X_test, y_test)])

    最后的輸出是:

    [9]	validation_0-error:0.0588

    也就是驗證集的准確率是94.12%。

    我們可以通過驗證集的准確率來判斷我們前面網格搜索調參是否起到了效果。實際處理的時候需要反復搜索參數並驗證。

    以上就是XGBoost的類庫使用總結了,希望可以幫到要用XGBoost解決實際問題的朋友們。

 

(歡迎轉載,轉載請注明出處。歡迎溝通交流: liujianping-ok@163.com)  


免責聲明!

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



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