XGBoost參數調優徹底指南(附Python代碼)

譯註:文內提供的代碼和運行結果有必定差別,能夠從這裏下載完整代碼對照參考。另外,我本身跟着教程作的時候,發現個人庫沒法解析字符串類型的特徵,因此只用其中一部分特徵作的,具體數值跟文章中不同,反而能夠幫助理解文章。因此你們其實也能夠小小修改一下代碼,不必定要徹底跟着教程作~ ^0^
須要提早安裝好的庫:numpy,matplotlib,pandas,xgboost,scikit-learnhtml

簡介

若是你的預測模型表現得有些不盡如人意,那就用XGBoost吧。XGBoost算法如今已經成爲不少數據工程師的重要武器。它是一種十分精緻的算法,能夠處理各類不規則的數據。
構造一個使用XGBoost的模型十分簡單。可是,提升這個模型的表現就有些困難(至少我以爲十分糾結)。這個算法使用了好幾個參數。因此爲了提升模型的表現,參數的調整十分必要。在解決實際問題的時候,有些問題是很難回答的——你須要調整哪些參數?這些參數要調到什麼值,才能達到理想的輸出?
這篇文章最適合剛剛接觸XGBoost的人閱讀。在這篇文章中,咱們會學到參數調優的技巧,以及XGboost相關的一些有用的知識。以及,咱們會用Python在一個數據集上實踐一下這個算法。java

你須要知道的

XGBoost(eXtreme Gradient Boosting)是Gradient Boosting算法的一個優化的版本。node

特別鳴謝:我我的十分感謝Mr Sudalai Rajkumar (aka SRK)大神的支持,目前他在AV Rank中位列第二。若是沒有他的幫助,就沒有這篇文章。在他的幫助下,咱們才能給無數的數據科學家指點迷津。給他一個大大的贊!python

內容列表

一、XGBoost的優點
二、理解XGBoost的參數
三、調整參數(含示例)git

一、XGBoost的優點

XGBoost算法能夠給預測模型帶來能力的提高。當我對它的表現有更多瞭解的時候,當我對它的高準確率背後的原理有更多瞭解的時候,我發現它具備不少優點:github

一、正則化

標準GBM的實現沒有像XGBoost這樣的正則化步驟。正則化對減小過擬合也是有幫助的。 實際上,XGBoost以「正則化提高(regularized boosting)」技術而聞名。web

二、並行處理

XGBoost能夠實現並行處理,相比GBM有了速度的飛躍。 不過,衆所周知,Boosting算法是順序處理的,它怎麼可能並行呢?每一課樹的構造都依賴於前一棵樹,那具體是什麼讓咱們能用多核處理器去構造一個樹呢?我但願你理解了這句話的意思。 XGBoost 也支持Hadoop實現。算法

三、高度的靈活性

XGBoost 容許用戶定義自定義優化目標和評價標準 它對模型增長了一個全新的維度,因此咱們的處理不會受到任何限制。多線程

四、缺失值處理

XGBoost內置處理缺失值的規則。 用戶須要提供一個和其它樣本不一樣的值,而後把它做爲一個參數傳進去,以此來做爲缺失值的取值。XGBoost在不一樣節點遇到缺失值時採用不一樣的處理方法,而且會學習將來遇到缺失值時的處理方法。函數

五、剪枝

當分裂時遇到一個負損失時,GBM會中止分裂。所以GBM其實是一個貪心算法。 XGBoost會一直分裂到指定的最大深度(max_depth),而後回過頭來剪枝。若是某個節點以後再也不有正值,它會去除這個分裂。 這種作法的優勢,當一個負損失(如-2)後面有個正損失(如+10)的時候,就顯現出來了。GBM會在-2處停下來,由於它遇到了一個負值。可是XGBoost會繼續分裂,而後發現這兩個分裂綜合起來會獲得+8,所以會保留這兩個分裂。

六、內置交叉驗證

XGBoost容許在每一輪boosting迭代中使用交叉驗證。所以,能夠方便地得到最優boosting迭代次數。 而GBM使用網格搜索,只能檢測有限個值。

七、在已有的模型基礎上繼續

XGBoost能夠在上一輪的結果上繼續訓練。這個特性在某些特定的應用上是一個巨大的優點。 sklearn中的GBM的實現也有這個功能,兩種算法在這一點上是一致的。

相信你已經對XGBoost強大的功能有了點概念。注意這是我本身總結出來的幾點,你若是有更多的想法,儘管在下面評論指出,我會更新這個列表的!

二、XGBoost的參數

XGBoost的做者把全部的參數分紅了三類:
一、通用參數:宏觀函數控制。
二、Booster參數:控制每一步的booster(tree/regression)。
三、學習目標參數:控制訓練目標的表現。
在這裏我會類比GBM來說解,因此做爲一種基礎知識。

通用參數

這些參數用來控制XGBoost的宏觀功能。

一、booster[默認gbtree]

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

二、silent[默認0]

當這個參數值爲1時,靜默模式開啓,不會輸出任何信息。 通常這個參數就保持默認的0,由於這樣能幫咱們更好地理解模型。

三、nthread[默認值爲最大可能的線程數]

這個參數用來進行多線程控制,應當輸入系統的核數。 若是你但願使用CPU所有的核,那就不要輸入這個參數,算法會自動檢測它。
還有兩個參數,XGBoost會自動設置,目前你不用管它。接下來我們一塊兒看booster參數。

booster參數

儘管有兩種booster可供選擇,我這裏只介紹tree booster,由於它的表現遠遠賽過linear booster,因此linear booster不多用到。

一、eta[默認0.3]

和GBM中的 learning rate 參數相似。 經過減小每一步的權重,能夠提升模型的魯棒性。 典型值爲0.01-0.2。

二、min_child_weight[默認1]

決定最小葉子節點樣本權重和。 和GBM的 min_child_leaf 參數相似,但不徹底同樣。XGBoost的這個參數是最小樣本權重的和,而GBM參數是最小樣本總數。 這個參數用於避免過擬合。當它的值較大時,能夠避免模型學習到局部的特殊樣本。 可是若是這個值太高,會致使欠擬合。這個參數須要使用CV來調整。

三、max_depth[默認6]

和GBM中的參數相同,這個值爲樹的最大深度。 這個值也是用來避免過擬合的。max_depth越大,模型會學到更具體更局部的樣本。 須要使用CV函數來進行調優。 典型值:3-10

四、max_leaf_nodes

樹上最大的節點或葉子的數量。 能夠替代max_depth的做用。由於若是生成的是二叉樹,一個深度爲n的樹最多生成n2個葉子。 若是定義了這個參數,GBM會忽略max_depth參數。

五、gamma[默認0]

在節點分裂時,只有分裂後損失函數的值降低了,纔會分裂這個節點。Gamma指定了節點分裂所需的最小損失函數降低值。 這個參數的值越大,算法越保守。這個參數的值和損失函數息息相關,因此是須要調整的。

六、max_delta_step[默認0]

這參數限制每棵樹權重改變的最大步長。若是這個參數的值爲0,那就意味着沒有約束。若是它被賦予了某個正值,那麼它會讓這個算法更加保守。 一般,這個參數不須要設置。可是當各種別的樣本十分不平衡時,它對邏輯迴歸是頗有幫助的。 這個參數通常用不到,可是你能夠挖掘出來它更多的用處。

七、subsample[默認1]

和GBM中的subsample參數如出一轍。這個參數控制對於每棵樹,隨機採樣的比例。 減少這個參數的值,算法會更加保守,避免過擬合。可是,若是這個值設置得太小,它可能會致使欠擬合。 典型值:0.5-1

八、colsample_bytree[默認1]

和GBM裏面的max_features參數相似。用來控制每棵隨機採樣的列數的佔比(每一列是一個特徵)。 典型值:0.5-1

九、colsample_bylevel[默認1]

用來控制樹的每一級的每一次分裂,對列數的採樣的佔比。 我我的通常不太用這個參數,由於subsample參數和colsample_bytree參數能夠起到相同的做用。可是若是感興趣,能夠挖掘這個參數更多的用處。

十、lambda[默認1]

權重的L2正則化項。(和Ridge regression相似)。 這個參數是用來控制XGBoost的正則化部分的。雖然大部分數據科學家不多用到這個參數,可是這個參數在減小過擬合上仍是能夠挖掘出更多用處的。

十一、alpha[默認1]

權重的L1正則化項。(和Lasso regression相似)。 能夠應用在很高維度的狀況下,使得算法的速度更快。

十二、scale_pos_weight[默認1]

在各種別樣本十分不平衡時,把這個參數設定爲一個正值,可使算法更快收斂。

學習目標參數

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

一、objective[默認reg:linear]

這個參數定義須要被最小化的損失函數。最經常使用的值有:
binary:logistic 二分類的邏輯迴歸,返回預測的機率(不是類別)。 multi:softmax 使用softmax的多分類器,返回預測的類別(不是機率)。
在這種狀況下,你還須要多設一個參數:num_class(類別數目)。 multi:softprob 和multi:softmax參數同樣,可是返回的是每一個數據屬於各個類別的機率。

二、eval_metric[默認值取決於objective參數的取值]

對於有效數據的度量方法。 對於迴歸問題,默認值是rmse,對於分類問題,默認值是error。 典型值有:
rmse 均方根偏差(∑Ni=1?2N??????√) mae 平均絕對偏差(∑Ni=1|?|N) logloss 負對數似然函數值 error 二分類錯誤率(閾值爲0.5) merror 多分類錯誤率 mlogloss 多分類logloss損失函數 auc 曲線下面積

三、seed(默認0)

隨機數的種子 設置它能夠復現隨機數據的結果,也能夠用於調整參數

若是你以前用的是Scikit-learn,你可能不太熟悉這些參數。可是有個好消息,python的XGBoost模塊有一個sklearn包,XGBClassifier。這個包中的參數是按sklearn風格命名的。會改變的函數名是:
一、eta ->learning_rate
二、lambda->reg_lambda
三、alpha->reg_alpha
你確定在疑惑爲啥我們沒有介紹和GBM中的’n_estimators’相似的參數。XGBClassifier中確實有一個相似的參數,可是,是在標準XGBoost實現中調用擬合函數時,把它做爲’num_boosting_rounds’參數傳入。

調整參數(含示例)

我已經對這些數據進行了一些處理:

City變量,由於類別太多,因此刪掉了一些類別。 DOB變量換算成年齡,並刪除了一些數據。 增長了 EMI_Loan_Submitted_Missing 變量。若是EMI_Loan_Submitted變量的數據缺失,則這個參數的值爲1。不然爲0。刪除了原先的EMI_Loan_Submitted變量。 EmployerName變量,由於類別太多,因此刪掉了一些類別。 由於Existing_EMI變量只有111個值缺失,因此缺失值補充爲中位數0。 增長了 Interest_Rate_Missing 變量。若是Interest_Rate變量的數據缺失,則這個參數的值爲1。不然爲0。刪除了原先的Interest_Rate變量。 刪除了Lead_Creation_Date,從直覺上這個特徵就對最終結果沒什麼幫助。 Loan_Amount_Applied, Loan_Tenure_Applied 兩個變量的缺項用中位數補足。 增長了 Loan_Amount_Submitted_Missing 變量。若是Loan_Amount_Submitted變量的數據缺失,則這個參數的值爲1。不然爲0。刪除了原先的Loan_Amount_Submitted變量。 增長了 Loan_Tenure_Submitted_Missing 變量。若是 Loan_Tenure_Submitted 變量的數據缺失,則這個參數的值爲1。不然爲0。刪除了原先的 Loan_Tenure_Submitted 變量。 刪除了LoggedIn, Salary_Account 兩個變量 增長了 Processing_Fee_Missing 變量。若是 Processing_Fee 變量的數據缺失,則這個參數的值爲1。不然爲0。刪除了原先的 Processing_Fee 變量。 Source前兩位不變,其它分紅不一樣的類別。 進行了量化和獨熱編碼(一位有效編碼)。

若是你有原始數據,能夠從資源庫裏面下載data_preparation的Ipython notebook 文件,而後本身過一遍這些步驟。

首先,import必要的庫,而後加載數據。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<code>#Import libraries:
import pandas as pd
import numpy as np
import xgboost as xgb
from xgboost.sklearn import XGBClassifier
from sklearn import cross_validation, metrics   #Additional     scklearn functions
from sklearn.grid_search import GridSearchCV   #Perforing grid search
 
import matplotlib.pylab as plt
%matplotlib inline
from matplotlib.pylab import rcParams
rcParams[ 'figure.figsize' ] = 12 , 4
 
train = pd.read_csv( 'train_modified.csv' )
target = 'Disbursed'
IDcol = 'ID'
</code>

注意我import了兩種XGBoost:

xgb - 直接引用xgboost。接下來會用到其中的「cv」函數。 XGBClassifier - 是xgboost的sklearn包。這個包容許咱們像GBM同樣使用Grid Search 和並行處理。

在向下進行以前,咱們先定義一個函數,它能夠幫助咱們創建XGBoost models 並進行交叉驗證。好消息是你能夠直接用下面的函數,之後再本身的models中也可使用它。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<code><code>def modelfit(alg, dtrain, predictors,useTrainCV=True, cv_folds= 5 , early_stopping_rounds= 50 ):
if useTrainCV:
     xgb_param = alg.get_xgb_params()
     xgtrain = xgb.DMatrix(dtrain[predictors].values, label=dtrain[target].values)
     cvresult = xgb.cv(xgb_param, xgtrain, num_boost_round=alg.get_params()[ 'n_estimators' ], nfold=cv_folds,
         metrics= 'auc' , early_stopping_rounds=early_stopping_rounds, show_progress=False)
     alg.set_params(n_estimators=cvresult.shape[ 0 ])
 
#Fit the algorithm on the data
alg.fit(dtrain[predictors], dtrain[ 'Disbursed' ],eval_metric= 'auc' )
 
#Predict training set:
dtrain_predictions = alg.predict(dtrain[predictors])
dtrain_predprob = alg.predict_proba(dtrain[predictors])[:, 1 ]
 
#Print model report:
print "\nModel Report"
print "Accuracy : %.4g" % metrics.accuracy_score(dtrain[ 'Disbursed' ].values, dtrain_predictions)
print "AUC Score (Train): %f" % metrics.roc_auc_score(dtrain[ 'Disbursed' ], dtrain_predprob)
 
feat_imp = pd.Series(alg.booster().get_fscore()).sort_values(ascending=False)
feat_imp.plot(kind= 'bar' , title= 'Feature Importances' )
plt.ylabel( 'Feature Importance Score' )
</code></code>

這個函數和GBM中使用的有些許不一樣。不過本文章的重點是講解重要的概念,而不是寫代碼。若是哪裏有不理解的地方,請在下面評論,不要有壓力。注意xgboost的sklearn包沒有「feature_importance」這個量度,可是get_fscore()函數有相同的功能。

參數調優的通常方法。

咱們會使用和GBM中類似的方法。須要進行以下步驟:
1. 選擇較高的學習速率(learning rate)。通常狀況下,學習速率的值爲0.1。可是,對於不一樣的問題,理想的學習速率有時候會在0.05到0.3之間波動。選擇對應於此學習速率的理想決策樹數量。XGBoost有一個頗有用的函數「cv」,這個函數能夠在每一次迭代中使用交叉驗證,並返回理想的決策樹數量。
2. 對於給定的學習速率和決策樹數量,進行決策樹特定參數調優(max_depth, min_child_weight, gamma, subsample, colsample_bytree)。在肯定一棵樹的過程當中,咱們能夠選擇不一樣的參數,待會兒我會舉例說明。
3. xgboost的正則化參數的調優。(lambda, alpha)。這些參數能夠下降模型的複雜度,從而提升模型的表現。
4. 下降學習速率,肯定理想參數。

我們一塊兒詳細地一步步進行這些操做。

第一步:肯定學習速率和tree_based 參數調優的估計器數目。

爲了肯定boosting 參數,咱們要先給其它參數一個初始值。我們先按以下方法取值:
一、max_depth = 5 :這個參數的取值最好在3-10之間。我選的起始值爲5,可是你也能夠選擇其它的值。起始值在4-6之間都是不錯的選擇。
二、min_child_weight = 1:在這裏選了一個比較小的值,由於這是一個極不平衡的分類問題。所以,某些葉子節點下的值會比較小。
三、gamma = 0: 起始值也能夠選其它比較小的值,在0.1到0.2之間就能夠。這個參數後繼也是要調整的。
四、subsample,colsample_bytree = 0.8: 這個是最多見的初始值了。典型值的範圍在0.5-0.9之間。
五、scale_pos_weight = 1: 這個值是由於類別十分不平衡。
注意哦,上面這些參數的值只是一個初始的估計值,後繼須要調優。這裏把學習速率就設成默認的0.1。而後用xgboost中的cv函數來肯定最佳的決策樹數量。前文中的函數能夠完成這個工做。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<code><code><code>#Choose all predictors except target & IDcols
predictors = [x for x in train.columns if x not in [target,IDcol]]
xgb1 = XGBClassifier(
  learning_rate = 0.1 ,
  n_estimators= 1000 ,
  max_depth= 5 ,
  min_child_weight= 1 ,
  gamma= 0 ,
  subsample= 0.8 ,
  colsample_bytree= 0.8 ,
  objective= 'binary:logistic' ,
  nthread= 4 ,
  scale_pos_weight= 1 ,
  seed= 27 )
modelfit(xgb1, train, predictors)
</code></code></code>

\

從輸出結果能夠看出,在學習速率爲0.1時,理想的決策樹數目是140。這個數字對你而言可能比較高,固然這也取決於你的系統的性能。

注意:在AUC(test)這裏你能夠看到測試集的AUC值。可是若是你在本身的系統上運行這些命令,並不會出現這個值。由於數據並不公開。這裏提供的值僅供參考。生成這個值的代碼部分已經被刪掉了。<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjwvYmxvY2txdW90ZT4NCjxoMSBpZD0="第二步-maxdepth-和-minweight-參數調優">第二步: max_depth 和 min_weight 參數調優

咱們先對這兩個參數調優,是由於它們對最終結果有很大的影響。首先,咱們先大範圍地粗調參數,而後再小範圍地微調。
注意:在這一節我會進行高負荷的柵格搜索(grid search),這個過程大約須要15-30分鐘甚至更久,具體取決於你係統的性能。你也能夠根據本身系統的性能選擇不一樣的值。

?
1
2
3
4
5
6
7
8
9
10
11
<code><code><code><code>param_test1 = {
  'max_depth' :range( 3 , 10 , 2 ),
  'min_child_weight' :range( 1 , 6 , 2 )
}
gsearch1 = GridSearchCV(estimator = XGBClassifier(         learning_rate = 0.1 , n_estimators= 140 , max_depth= 5 ,
min_child_weight= 1 , gamma= 0 , subsample= 0.8 ,             colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 ,     scale_pos_weight= 1 , seed= 27 ),
  param_grid = param_test1,     scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch1.fit(train[predictors],train[target])
gsearch1.grid_scores_, gsearch1.best_params_,     gsearch1.best_score_
</code></code></code></code>

輸出結果

至此,咱們對於數值進行了較大跨度的12中不一樣的排列組合,能夠看出理想的max_depth值爲5,理想的min_child_weight值爲5。在這個值附近咱們能夠再進一步調整,來找出理想值。咱們把上下範圍各拓展1,由於以前咱們進行組合的時候,參數調整的步長是2。

?
1
2
3
4
5
6
7
8
9
10
11
<code><code><code><code><code>param_test2 = {
  'max_depth' :[ 4 , 5 , 6 ],
  'min_child_weight' :[ 4 , 5 , 6 ]
}
gsearch2 = GridSearchCV(estimator = XGBClassifier(     learning_rate= 0.1 , n_estimators= 140 , max_depth= 5 ,
  min_child_weight= 2 , gamma= 0 , subsample= 0.8 , colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test2, scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch2.fit(train[predictors],train[target])
gsearch2.grid_scores_, gsearch2.best_params_,     gsearch2.best_score_
</code></code></code></code></code>

輸出結果

至此,咱們獲得max_depth的理想取值爲4,min_child_weight的理想取值爲6。同時,咱們還能看到cv的得分有了小小一點提升。須要注意的一點是,隨着模型表現的提高,進一步提高的難度是指數級上升的,尤爲是你的表現已經接近完美的時候。固然啦,你會發現,雖然min_child_weight的理想取值是6,可是咱們還沒嘗試過大於6的取值。像下面這樣,就能夠嘗試其它值。

?
1
2
3
4
5
6
7
8
9
10
11
12
<code><code><code><code><code><code>param_test2b = {
  'min_child_weight' :[ 6 , 8 , 10 , 12 ]
  }
gsearch2b = GridSearchCV(estimator = XGBClassifier(     learning_rate= 0.1 , n_estimators= 140 , max_depth= 4 ,
  min_child_weight= 2 , gamma= 0 , subsample= 0.8 ,     colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test2b,     scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch2b.fit(train[predictors],train[target])
 
modelfit(gsearch3.best_estimator_, train, predictors)
gsearch2b.grid_scores_, gsearch2b.best_params_,     gsearch2b.best_score_
</code></code></code></code></code></code>

輸出結果

咱們能夠看出,6確確實實是理想的取值了。

第三步:gamma參數調優

在已經調整好其它參數的基礎上,咱們能夠進行gamma參數的調優了。Gamma參數取值範圍能夠很大,我這裏把取值範圍設置爲5了。你其實也能夠取更精確的gamma值。

?
1
2
3
4
5
6
7
8
9
10
<code><code><code><code><code><code><code>param_test3 = {
  'gamma' :[i/ 10.0 for i in range( 0 , 5 )]
}
gsearch3 = GridSearchCV(estimator = XGBClassifier( learning_rate = 0.1 , n_estimators= 140 , max_depth= 4 ,
  min_child_weight= 6 , gamma= 0 , subsample= 0.8 , colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test3, scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch3.fit(train[predictors],train[target])
gsearch3.grid_scores_, gsearch3.best_params_, gsearch3.best_score_
</code></code></code></code></code></code></code>

從這裏能夠看出來,咱們在第一步調參時設置的初始gamma值就是比較合適的。也就是說,理想的gamma值爲0。在這個過程開始以前,最好從新調整boosting回合,由於參數都有變化。
gamma
從這裏能夠看出,得分提升了。因此,最終獲得的參數是:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<code><code><code><code><code><code><code><code>xgb2 = XGBClassifier(
  learning_rate = 0.1 ,
  n_estimators= 1000 ,
  max_depth= 4 ,
  min_child_weight= 6 ,
  gamma= 0 ,
  subsample= 0.8 ,
  colsample_bytree= 0.8 ,
  objective= 'binary:logistic' ,
  nthread= 4 ,
scale_pos_weight= 1 ,
seed= 27 )
modelfit(xgb2, train, predictors)
</code></code></code></code></code></code></code></code>

最終參數

第四步:調整subsample 和 colsample_bytree 參數

下一步是嘗試不一樣的subsample 和 colsample_bytree 參數。咱們分兩個階段來進行這個步驟。這兩個步驟都取0.6,0.7,0.8,0.9做爲起始值。

?
1
2
3
4
5
6
7
8
9
10
11
<code><code><code><code><code><code><code><code><code>param_test4 = {
  'subsample' :[i/ 10.0 for i in range( 6 , 10 )],
  'colsample_bytree' :[i/ 10.0 for i in range( 6 , 10 )]
}
gsearch4 = GridSearchCV(estimator = XGBClassifier( learning_rate = 0.1 , n_estimators= 177 , max_depth= 3 ,
  min_child_weight= 4 , gamma= 0.1 , subsample= 0.8 , colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test4, scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch4.fit(train[predictors],train[target])
gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_
</code></code></code></code></code></code></code></code></code>

gsearch4

從這裏能夠看出來,subsample 和 colsample_bytree 參數的理想取值都是0.8。如今,咱們以0.05爲步長,在這個值附近嘗試取值。

?
1
2
3
4
5
6
7
8
9
10
<code><code><code><code><code><code><code><code><code><code>param_test5 = {
  'subsample' :[i/ 100.0 for i in range( 75 , 90 , 5 )],
  'colsample_bytree' :[i/ 100.0 for i in range( 75 , 90 , 5 )]
}
gsearch5 = GridSearchCV(estimator = XGBClassifier( learning_rate = 0.1 , n_estimators= 177 , max_depth= 4 ,
  min_child_weight= 6 , gamma= 0 , subsample= 0.8 , colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test5, scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch5.fit(train[predictors],train[target])
</code></code></code></code></code></code></code></code></code></code>

output

咱們獲得的理想取值仍是原來的值。所以,最終的理想取值是:

subsample: 0.8 colsample_bytree: 0.8

第五步:正則化參數調優。

下一步是應用正則化來下降過擬合。因爲gamma函數提供了一種更加有效地下降過擬合的方法,大部分人不多會用到這個參數。可是咱們在這裏也能夠嘗試用一下這個參數。我會在這裏調整’reg_alpha’參數,而後’reg_lambda’參數留給你來完成。

?
1
2
3
4
5
6
7
8
9
10
<code><code><code><code><code><code><code><code><code><code><code>param_test6 = {
  'reg_alpha' :[1e- 5 , 1e- 2 , 0.1 , 1 , 100 ]
}
gsearch6 = GridSearchCV(estimator = XGBClassifier( learning_rate = 0.1 , n_estimators= 177 , max_depth= 4 ,
  min_child_weight= 6 , gamma= 0.1 , subsample= 0.8 , colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test6, scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch6.fit(train[predictors],train[target])
gsearch6.grid_scores_, gsearch6.best_params_, gsearch6.best_score_
</code></code></code></code></code></code></code></code></code></code></code>

output

咱們能夠看到,相比以前的結果,CV的得分甚至還下降了。可是咱們以前使用的取值是十分粗糙的,咱們在這裏選取一個比較靠近理想值(0.01)的取值,來看看是否有更好的表現。

?
1
2
3
4
5
6
7
8
9
10
<code><code><code><code><code><code><code><code><code><code><code><code>param_test7 = {
  'reg_alpha' :[ 0 , 0.001 , 0.005 , 0.01 , 0.05 ]
}
gsearch7 = GridSearchCV(estimator = XGBClassifier( learning_rate = 0.1 , n_estimators= 177 , max_depth= 4 ,
  min_child_weight= 6 , gamma= 0.1 , subsample= 0.8 , colsample_bytree= 0.8 ,
  objective= 'binary:logistic' , nthread= 4 , scale_pos_weight= 1 ,seed= 27 ),
  param_grid = param_test7, scoring= 'roc_auc' ,n_jobs= 4 ,iid=False, cv= 5 )
gsearch7.fit(train[predictors],train[target])
gsearch7.grid_scores_, gsearch7.best_params_, gsearch7.best_score_
</code></code></code></code></code></code></code></code></code></code></code></code>

output7

能夠看到,CV的得分提升了。如今,咱們在模型中來使用正則化參數,來看看這個參數的影響。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code><code><code><code><code><code><code><code><code><code><code><code><code>xgb3 = XGBClassifier(
  learning_rate = 0.1 ,
  n_estimators= 1000 ,
  max_depth= 4 ,
  min_child_weight= 6 ,
  gamma= 0 ,
  subsample= 0.8 ,
  colsample_bytree= 0.8 ,
  reg_alpha= 0.005 ,
  objective= 'binary:logistic' ,
  nthread= 4 ,
  scale_pos_weight= 1 ,
  seed= 27 )
modelfit(xgb3, train, predictors)
</code></code></code></code></code></code></code></code></code></code></code></code></code>

out_put3

而後咱們發現性能有了小幅度提升。

第6步:下降學習速率

最後,咱們使用較低的學習速率,以及使用更多的決策樹。咱們能夠用XGBoost中的CV函數來進行這一步工做。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code><code><code><code><code><code><code><code><code><code><code><code><code><code>xgb4 = XGBClassifier(
  learning_rate = 0.01 ,
  n_estimators= 5000 ,
  max_depth= 4 ,
  min_child_weight= 6 ,
  gamma= 0 ,
  subsample= 0.8 ,
  colsample_bytree= 0.8 ,
  reg_alpha= 0.005 ,
  objective= 'binary:logistic' ,
  nthread= 4 ,
  scale_pos_weight= 1 ,
  seed= 27 )
modelfit(xgb4, train, predictors)
</code></code></code></code></code></code></code></code></code></code></code></code></code></code>

此處輸入圖片的描述
加載中...

至此,你能夠看到模型的表現有了大幅提高,調整每一個參數帶來的影響也更加清楚了。
在文章的末尾,我想分享兩個重要的思想:
一、僅僅靠參數的調整和模型的小幅優化,想要讓模型的表現有個大幅度提高是不可能的。GBM的最高得分是0.8487,XGBoost的最高得分是0.8494。確實是有必定的提高,可是沒有達到質的飛躍。
二、要想讓模型的表現有一個質的飛躍,須要依靠其餘的手段,諸如,特徵工程(feature egineering) ,模型組合(ensemble of model),以及堆疊(stacking)等。

 

結束語

這篇文章主要講了如何提高XGBoost模型的表現。首先,咱們介紹了相比於GBM,爲什麼XGBoost能夠取得這麼好的表現。緊接着,咱們介紹了每一個參數的細節。咱們定義了一個能夠重複使用的構造模型的函數。最後,咱們討論了使用XGBoost解決問題的通常方法,在AV Data Hackathon 3.x problem數據上實踐了這些方法。但願看過這篇文章以後,你能有所收穫,下次使用XGBoost解決問題的時候能夠更有信心哦~

相關文章
相關標籤/搜索