1. 程式人生 > >GridSearchCV 與 RandomizedSearchCV 調參

GridSearchCV 與 RandomizedSearchCV 調參

  好久沒寫部落格了,原因是最近比較忙,一下報了兩個比賽,今天終於最後一個比賽的初賽都結束了,抽點小空趕緊總結一下,先彙報下成績吧。IJCAI2018 阿里媽媽廣告演算法大賽,初賽第六。FASHIONAI屬性識別大賽初賽25 。複賽加油,爭取取得更好的成績。

   昨天和前天都加班調參了,但是由於是新手,所以遇到很多困難,剛好看到一片部落格,關於調參的,所以這裡我就引過來,以備後面查閱和使用的方便,如果有侵權,請聯絡我。

   當使用一些大規模整合的演算法時,引數的問題就出來了,比如說 XGBoost的引數大概在20個左右,GBDT的引數個數也在同一個級別,這種時候,會調參和不會調參在同樣的資料集上效果可能就是兩碼事了。這裡藉著做阿里天池大賽的機會和大家分享一些使用sklearn裡封裝好的函式 GridSearchCV 與 RandomizedSearchCV 進行調參的方法和技巧,分類器就以常用的XGBoostClassifier為例 


這裡主要介紹一下這兩個函式的應用

GridSearchCV

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

交叉驗證的概念也很簡單

· 將訓練資料集劃分為K份,K一般為10
· 依次取其中一份為驗證集,其餘為訓練集訓練分類器,測試分類器在驗證集上的精度 
· 取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("/traindata_4_3.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 logloss(act, pred):
    epsilon = 1e-15
    pred = sp.maximum(epsilon, pred)
    pred = sp.minimum(1-epsilon, pred)
    ll = sum(act*sp.log(pred) + sp.subtract(1, act)*sp.log(sp.subtract(1, pred)))
    ll = ll * -1.0/len(act)
    return ll

#這裡的greater_is_better引數決定了自定義的評價指標是越大越好還是越小越好
loss  = make_scorer(logloss, greater_is_better=False)
score = make_scorer(logloss, 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("/traindata.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_)

不過建議還是使用隨機的搜尋。