當GridSearch趕上XGBoost 一段代碼解決調參問題

寫在最前

數據比賽,GBM(Gredient Boosting Machine)少不了,咱們最多見的就是XGBoost和LightGBM。html

模型是在數據比賽中尤其重要的,可是實際上,在比賽的過程當中,大部分朋友在模型上花的時間倒是相對較少的,你們都傾向於將寶貴的時間留在特徵提取與模型融合這些方面。在實戰中,咱們會先作一個baseline的demo,儘量快儘量多的挖掘出模型的潛力,以便後期將精力花在特徵和模型融合上。這裏就須要一些調參功底。git

本文從這兩種模型的一共百餘參數中選取重要的十餘個進行探討研究。並給你們展現快速輕量級的調參方式。固然,有更高一步要求的朋友,仍是得戳LightGBMXGBoost這兩個官方文檔連接。算法

爲了更好的試驗,我將預處理後的數據放在百度雲上。你們戳連接下載。apache

XGBoost 的一些重要參數

XGBoost的參數一共分爲三類:數組

  1. 通用參數:宏觀函數控制。
  2. Booster參數:控制每一步的booster(tree/regression)。booster參數通常能夠調控模型的效果和計算代價。咱們所說的調參,很這是大程度上都是在調整booster參數。
  3. 學習目標參數:控制訓練目標的表現。咱們對於問題的劃分主要體如今學習目標參數上。好比咱們要作分類仍是迴歸,作二分類仍是多分類,這都是目標參數所提供的。

Note: 我下面介紹的參數都是我以爲比較重要的, 完整參數請戳官方文檔bash

通用參數

  1. booster:咱們有兩種參數選擇,gbtreegblinear。gbtree是採用樹的結構來運行數據,而gblinear是基於線性模型。
  2. silent:靜默模式,爲1時模型運行不輸出。
  3. nthread: 使用線程數,通常咱們設置成-1,使用全部線程。若是有須要,咱們設置成多少就是用多少線程。

Booster參數

  1. n_estimator: 也做num_boosting_roundsdom

    這是生成的最大樹的數目,也是最大的迭代次數。機器學習

  2. learning_rate: 有時也叫做eta,系統默認值爲0.3,。函數

    每一步迭代的步長,很重要。太大了運行準確率不高,過小了運行速度慢。咱們通常使用比默認值小一點,0.1左右就很好。工具

  3. gamma:系統默認爲0,咱們也經常使用0

    在節點分裂時,只有分裂後損失函數的值降低了,纔會分裂這個節點。gamma指定了節點分裂所需的最小損失函數降低值。 這個參數的值越大,算法越保守。由於gamma值越大的時候,損失函數降低更多才能夠分裂節點。因此樹生成的時候更不容易分裂節點。範圍: [0,∞]

  4. subsample:系統默認爲1

    這個參數控制對於每棵樹,隨機採樣的比例。減少這個參數的值,算法會更加保守,避免過擬合。可是,若是這個值設置得太小,它可能會致使欠擬合。 典型值:0.5-10.5表明平均採樣,防止過擬合. 範圍: (0,1]注意不可取0

  5. colsample_bytree:系統默認值爲1。咱們通常設置成0.8左右。

    用來控制每棵隨機採樣的列數的佔比(每一列是一個特徵)。 典型值:0.5-1範圍: (0,1]

  6. colsample_bylevel:默認爲1,咱們也設置爲1.

    這個就相比於前一個更加細緻了,它指的是每棵樹每次節點分裂的時候列採樣的比例

  7. max_depth: 系統默認值爲6

    咱們經常使用3-10之間的數字。這個值爲樹的最大深度。這個值是用來控制過擬合的。max_depth越大,模型學習的更加具體。設置爲0表明沒有限制,範圍: [0,∞]

  8. max_delta_step:默認0,咱們經常使用0.

    這個參數限制了每棵樹權重改變的最大步長,若是這個參數的值爲0,則意味着沒有約束。若是他被賦予了某一個正值,則是這個算法更加保守。一般,這個參數咱們不須要設置,可是當個類別的樣本極不平衡的時候,這個參數對邏輯迴歸優化器是頗有幫助的。

  9. lambda:也稱reg_lambda,默認值爲0

    權重的L2正則化項。(和Ridge regression相似)。這個參數是用來控制XGBoost的正則化部分的。這個參數在減小過擬合上頗有幫助。

  10. alpha:也稱reg_alpha默認爲0,

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

  11. scale_pos_weight:默認爲1

    在各種別樣本十分不平衡時,把這個參數設定爲一個正值,可使算法更快收斂。一般能夠將其設置爲負樣本的數目與正樣本數目的比值。

學習目標參數

objective [缺省值=reg:linear]

  • reg:linear– 線性迴歸
  • reg:logistic – 邏輯迴歸
  • binary:logistic – 二分類邏輯迴歸,輸出爲機率
  • binary:logitraw – 二分類邏輯迴歸,輸出的結果爲wTx
  • count:poisson – 計數問題的poisson迴歸,輸出結果爲poisson分佈。在poisson迴歸中,max_delta_step的缺省值爲0.7 (used to safeguard optimization)
  • multi:softmax – 設置 XGBoost 使用softmax目標函數作多分類,須要設置參數num_class(類別個數)
  • multi:softprob – 如同softmax,可是輸出結果爲ndata*nclass的向量,其中的值是每一個數據分爲每一個類的機率。

eval_metric [缺省值=經過目標函數選擇]

  • rmse: 均方根偏差
  • mae: 平均絕對值偏差
  • logloss: negative log-likelihood
  • error: 二分類錯誤率。其值經過錯誤分類數目與所有分類數目比值獲得。對於預測,預測值大於0.5被認爲是正類,其它歸爲負類。 error@t: 不一樣的劃分閾值能夠經過 ‘t’進行設置
  • merror: 多分類錯誤率,計算公式爲(wrong cases)/(all cases)
  • mlogloss: 多分類log損失
  • auc: 曲線下的面積
  • ndcg: Normalized Discounted Cumulative Gain
  • map: 平均正確率

通常來講,咱們都會使用xgboost.train(params, dtrain)函數來訓練咱們的模型。這裏的params指的是booster參數。

兩種基本的實例

咱們要注意的是,在xgboost中想要進行二分類處理的時候,咱們僅僅在 objective中設置成 binary,會發現輸出仍然是一堆連續的值。這是由於它輸出的是模型預測的全部機率中最大的那個值。咱們能夠後續對這些機率進行條件處理獲得最終類別,或者直接調用xgboost中的XGBClassifier()類,但這兩種函數的寫法不太同樣。你們看我下面的例子。

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

train_data = pd.read_csv('train.csv')   # 讀取數據
y = train_data.pop('30').values   # 用pop方式將訓練數據中的標籤值y取出來,做爲訓練目標,這裏的‘30’是標籤的列名
col = train_data.columns   
x = train_data[col].values  # 剩下的列做爲訓練數據
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0)   # 分訓練集和驗證集
train = xgb.DMatrix(train_x, train_y)
valid = xgb.DMatrix(valid_x, valid_y)   # train函數下須要傳入一個Dmatrix值,具體用法如代碼所示

params = {
            'max_depth': 15,
            'learning_rate': 0.1,
            'n_estimators': 2000,
            'min_child_weight': 5,
            'max_delta_step': 0,
            'subsample': 0.8,
            'colsample_bytree': 0.7,
            'reg_alpha': 0,
            'reg_lambda': 0.4,
            'scale_pos_weight': 0.8,
            'silent': True,
            'objective': 'binary:logistic',
            'missing': None,
            'eval_metric': 'auc',
            'seed': 1440,
            'gamma': 0
}    # 這裏的params特指booster參數,注意這個eva_metric是評估函數

xlf = xgb.train(params, train, evals=[(valid, 'eval')], 
                num_boost_round=2000, early_stopping_rounds=30, verbose_eval=True)   
                # 訓練,注意驗證集的寫法, 還有early_stopping寫法,這裏指的是30輪迭代中效果未增加便中止訓練
y_pred = xlf.predict(valid_x, ntree_limit=xlf.best_ntree_limit) 
# xgboost沒有直接使用效果最好的樹做爲模型的機制,這裏採用最大樹深限制的方法,目的是獲取剛剛early_stopping效果最好的,實測性能能夠
auc_score = roc_auc_score(valid_y, y_pred)  # 算一下預測結果的roc值

複製代碼

以上是xgboost.train()寫法,這是xgboost最原始的封裝函數。這樣訓練咱們預測輸出的是一串連續值,是xgboost在這幾個類別上機率最大的機率值。咱們若是想要獲得咱們的分類結果,還須要進行其餘操做。

幸運的是,xgboost爲了貼合sklearn的使用,好比gridsearch這些實用工具,又開發了XGBoostClassifier()XGBoostRegression()兩個函數。能夠更加簡單快捷的進行分類和迴歸處理。注意xgboost的sklearn包沒有 feature_importance 這個量度,可是get_fscore()函數有相同的功能。固然,爲了和sklearn保持一致,寫法也發生變化,具體請看下面代碼:

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

train_data = pd.read_csv('train.csv')   # 讀取數據
y = train_data.pop('30').values   # 用pop方式將訓練數據中的標籤值y取出來,做爲訓練目標,這裏的‘30’是標籤的列名
col = train_data.columns   
x = train_data[col].values  # 剩下的列做爲訓練數據
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0)   # 分訓練集和驗證集
# 這裏不須要Dmatrix

xlf = xgb.XGBClassifier(max_depth=10,
			learning_rate=0.01,
			n_estimators=2000,
			silent=True,
			objective='binary:logistic',
			nthread=-1,
			gamma=0,
			min_child_weight=1,
			max_delta_step=0,
			subsample=0.85,
			colsample_bytree=0.7,
			colsample_bylevel=1,
			reg_alpha=0,
			reg_lambda=1,
			scale_pos_weight=1,
			seed=1440,
			missing=None)
xlf.fit(train_x, train_y, eval_metric='error', verbose=True, eval_set=[(valid_x, valid_y)], early_stopping_rounds=30)
# 這個verbose主要是調節系統輸出的,若是設置成10,即是每迭代10次就有輸出。
# 注意咱們這裏eval_metric=‘error’即是準確率。這裏面並無accuracy命名的函數,網上大多例子爲auc,我這裏特地放了個error。
y_pred = xlf.predict(valid_x, ntree_limit=xlf.best_ntree_limit)
auc_score = roc_auc_score(valid_y, y_pred)
y_pred = xlf.predict(valid_x, ntree_limit=xlf.best_ntree_limit) 
# xgboost沒有直接使用效果最好的樹做爲模型的機制,這裏採用最大樹深限制的方法,目的是獲取剛剛early_stopping效果最好的,實測性能能夠
auc_score = roc_auc_score(valid_y, y_pred)  # 算一下預測結果的roc值

複製代碼

那麼咱們介紹了這麼多,重點就來了:如何又快又好的調參?首先咱們須要瞭解grid search是個什麼原理。

GridSearch 簡介

這是一種調參手段;窮舉搜索:在全部候選的參數選擇中,經過循環遍歷,嘗試每一種可能性,表現最好的參數就是最終的結果。其原理就像是在數組裏找最大值。(爲何叫網格搜索?以有兩個參數的模型爲例,參數a有3種可能,參數b有4種可能,把全部可能性列出來,能夠表示成一個3*4的表格,其中每一個cell就是一個網格,循環過程就像是在每一個網格里遍歷、搜索,因此叫grid search)

其實這個就跟咱們經常使用的遍歷是同樣的。建議你們使用sklearn裏面的GridSearch函數,簡潔速度快。

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

train_data = pd.read_csv('train.csv')   # 讀取數據
y = train_data.pop('30').values   # 用pop方式將訓練數據中的標籤值y取出來,做爲訓練目標,這裏的‘30’是標籤的列名
col = train_data.columns   
x = train_data[col].values  # 剩下的列做爲訓練數據
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0)   # 分訓練集和驗證集
# 這裏不須要Dmatrix

parameters = {
              'max_depth': [5, 10, 15, 20, 25],
              'learning_rate': [0.01, 0.02, 0.05, 0.1, 0.15],
              'n_estimators': [500, 1000, 2000, 3000, 5000],
              'min_child_weight': [0, 2, 5, 10, 20],
              'max_delta_step': [0, 0.2, 0.6, 1, 2],
              'subsample': [0.6, 0.7, 0.8, 0.85, 0.95],
              'colsample_bytree': [0.5, 0.6, 0.7, 0.8, 0.9],
              'reg_alpha': [0, 0.25, 0.5, 0.75, 1],
              'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1],
              'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]

}

xlf = xgb.XGBClassifier(max_depth=10,
			learning_rate=0.01,
			n_estimators=2000,
			silent=True,
			objective='binary:logistic',
			nthread=-1,
			gamma=0,
			min_child_weight=1,
			max_delta_step=0,
			subsample=0.85,
			colsample_bytree=0.7,
			colsample_bylevel=1,
			reg_alpha=0,
			reg_lambda=1,
			scale_pos_weight=1,
			seed=1440,
			missing=None)
			
# 有了gridsearch咱們便不須要fit函數
gsearch = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)
gsearch.fit(train_x, train_y)

print("Best score: %0.3f" % gsearch.best_score_)
print("Best parameters set:")
best_parameters = gsearch.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
    print("\t%s: %r" % (param_name, best_parameters[param_name]))

複製代碼

咱們須要注意的是,Grid Search 須要交叉驗證支持的。這裏的cv=3,是個int數,就表明3-折驗證。實際上cv能夠是一個對象,也能夠是其餘類型。分別表明不一樣的方式驗證。具體的你們可看下面這段表述。

Possible inputs for cv are:
        - None, to use the default 3-fold cross-validation,
        - integer, to specify the number of folds.
        - An object to be used as a cross-validation generator.
        - An iterable yielding train/test splits.
複製代碼

參考文獻:

機器學習之-xgboost

相關文章
相關標籤/搜索