1. 程式人生 > >機器學習教程 之 引數搜尋:GridSearchCV 與 RandomizedSearchCV || 以阿里IJCAI廣告推薦資料集與XGBoostClassifier分類器為例

機器學習教程 之 引數搜尋:GridSearchCV 與 RandomizedSearchCV || 以阿里IJCAI廣告推薦資料集與XGBoostClassifier分類器為例

在使用一些比較基礎的分類器時,需要人為調整的引數是比較少的,比如說K-Neighbor的K和SVM的C,通常而言直接使用sklearn裡的預設值就能取得比較好的效果了。
但是,當使用一些大規模整合的演算法時,引數的問題就出來了,比如說 XGBoost的引數大概在20個左右,GBDT的引數個數也在同一個級別,這種時候,會調參和不會調參在同樣的資料集上效果可能就是兩碼事了。這裡藉著做阿里天池大賽的機會和大家分享一些使用sklearn裡封裝好的函式 GridSearchCV 與 RandomizedSearchCV 進行調參的方法和技巧,分類器就以常用的XGBoostClassifier為例
這裡主要介紹一下這兩個函式的應用

GridSearchCV

GridSearchCV的名字其實可以拆分為兩部分,GridSearch和CV,即網格搜尋和交叉驗證。
這兩個概念都比較好理解,網格搜尋,搜尋的是引數,即在指定的引數範圍內,按步長依次調整引數,利用調整的引數訓練學習器,從所有的引數中找到在驗證集上精度最高的引數,這其實是一個迴圈和比較的過程。
GridSearchCV可以保證在指定的引數範圍內找到精度最高的引數,但是這也是網格搜尋的缺陷所在,它要求遍歷所有可能引數的組合,在面對大資料集和多引數的情況下,非常耗時。這也是我通常不會使用GridSearchCV的原因,一般會採用後一種RandomizedSearchCV隨機引數搜尋的方法。

交叉驗證的概念也很簡單

· 將訓練資料集劃分為K份,K一般為10(我個人取3到5比較多)
· 依次取其中一份為驗證集,其餘為訓練集訓練分類器,測試分類器在驗證集上的精度
· 取K次實驗的平均精度為該分類器的平均精度

網格搜尋就是利用交叉驗證的形式比較每一個引數下訓練器的精度的,但是交叉驗證也要求大量的計算資源,加重了網格搜尋的搜尋時間

接下來以阿里IJCAI廣告推薦資料集與XGBoostClassifier分類器為例,用程式碼的形式說明sklearn中GridSearchCV的使用方法

import numpy as np
import pandas as pd
import
xgboost as xgb from sklearn.grid_search import GridSearchCV #匯入訓練資料 traindata = pd.read_csv("/home/pmqc01/LiangjunFeng/traindata_4_3_2.txt",sep = ',') traindata = traindata.set_index('instance_id') trainlabel = traindata['is_trade'] del traindata['is_trade'] print(traindata.shape,trainlabel.shape) #分類器使用 xgboost clf1 = xgb.XGBClassifier() #設定網格搜尋的xgboost引數搜尋範圍,值搜尋XGBoost的主要6個引數 param_dist = { 'n_estimators':range(80,200,4), 'max_depth':range(2,15,1), 'learning_rate':np.linspace(0.01,2,20), 'subsample':np.linspace(0.7,0.9,20), 'colsample_bytree':np.linspace(0.5,0.98,10), 'min_child_weight':range(1,9,1) } #GridSearchCV引數說明,clf1設定訓練的學習器 #param_dist字典型別,放入引數搜尋範圍 #scoring = 'neg_log_loss',精度評價方式設定為“neg_log_loss“ #n_iter=300,訓練300次,數值越大,獲得的引數精度越大,但是搜尋時間越長 #n_jobs = -1,使用所有的CPU進行訓練,預設為1,使用1個CPU grid = GridSearchCV(clf1,param_dist,cv = 3,scoring = 'neg_log_loss',n_iter=300,n_jobs = -1) #在訓練集上訓練 grid.fit(traindata.values,np.ravel(trainlabel.values)) #返回最優的訓練器 best_estimator = grid.best_estimator_ print(best_estimator) #輸出最優訓練器的精度 print(grid.best_score_)

這裡關於網格搜尋的幾個引數再說明一下,評分引數“scoring“,需要根據實際的評價標準設定,阿里的IJCAI的標準是’neg_log_loss’,所以這裡設定的是’neg_log_loss’,sklearn中備選的評價標準有一下:

這裡寫圖片描述

在一些情況下,sklearn中沒有現成的評價函式,sklearn是允許我們自己的定義的,但需要注意格式,接下來給個例子

import numpy as np
from sklearn.metrics import make_scorer

def my_custom_loss_func(ground_truth, predictions):
    diff = np.abs(ground_truth - predictions).max()
    return np.log(1 + diff)

#這裡的greater_is_better引數決定了自定義的評價指標是越大越好還是越小越好
loss  = make_scorer(my_custom_loss_func, greater_is_better=False)
score = make_scorer(my_custom_loss_func, greater_is_better=True)

定義好以後,再將其代入GridSearchCV函式就好

這裡再貼一下常用的整合學習演算法比較重要的需要調參的引數,供大家參考
這裡寫圖片描述

RandomizedSearchCV

RandomizedSearchCV的使用方法其實是和GridSearchCV一致的,但它以隨機在引數空間中取樣的方式代替了GridSearchCV對於引數的網格搜尋,在對於有連續變數的引數時,RandomizedSearchCV會將其當作一個分佈進行取樣這是網格搜尋做不到的,它的搜尋能力取決於設定的n_iter引數,同樣的給出程式碼

import numpy as np
import pandas as pd
import xgboost as xgb
from sklearn.grid_search import RandomizedSearchCV


#匯入訓練資料
traindata = pd.read_csv("/home/pmqc01/LiangjunFeng/traindata_4_3_2.txt",sep = ',')
traindata = traindata.set_index('instance_id')
trainlabel = traindata['is_trade']
del traindata['is_trade']
print(traindata.shape,trainlabel.shape)


#分類器使用 xgboost
clf1 = xgb.XGBClassifier()

#設定搜尋的xgboost引數搜尋範圍,值搜尋XGBoost的主要6個引數
param_dist = {
        'n_estimators':range(80,200,4),
        'max_depth':range(2,15,1),
        'learning_rate':np.linspace(0.01,2,20),
        'subsample':np.linspace(0.7,0.9,20),
        'colsample_bytree':np.linspace(0.5,0.98,10),
        'min_child_weight':range(1,9,1)
        }

#RandomizedSearchCV引數說明,clf1設定訓練的學習器
#param_dist字典型別,放入引數搜尋範圍
#scoring = 'neg_log_loss',精度評價方式設定為“neg_log_loss“
#n_iter=300,訓練300次,數值越大,獲得的引數精度越大,但是搜尋時間越長
#n_jobs = -1,使用所有的CPU進行訓練,預設為1,使用1個CPU
grid = RandomizedSearchCV(clf1,param_dist,cv = 3,scoring = 'neg_log_loss',n_iter=300,n_jobs = -1)

#在訓練集上訓練
grid.fit(traindata.values,np.ravel(trainlabel.values))
#返回最優的訓練器
best_estimator = grid.best_estimator_
print(best_estimator)
#輸出最優訓練器的精度
print(grid.best_score_)

這裡要注意,雖然GridSearchCV 與 RandomizedSearchCV同樣都有引數n_iter,但其實質是不一樣的,官方文件對於這裡的解釋是

In contrast to GridSearchCV, not all parameter values are tried out, but rather a fixed number of parameter settings is sampled from the specified distributions. The number of parameter settings that are tried is given by n_iter.

If all parameters are presented as a list, sampling without replacement is performed. If at least one parameter is given as a distribution, sampling with replacement is used. It is highly recommended to use continuous distributions for continuous parameters.

即RandomizedSearchCV的主要特點還是引數的選取是隨機的,不保證每一個引數都能夠遍歷,還有對於連續引數是當作一個分佈來處理的