Python機器學習筆記:Grid SearchCV(網格搜索)

  在機器學習模型中,須要人工選擇的參數稱爲超參數。好比隨機森林中決策樹的個數,人工神經網絡模型中隱藏層層數和每層的節點個數,正則項中常數大小等等,他們都須要事先指定。超參數選擇不恰當,就會出現欠擬合或者過擬合的問題。而在選擇超參數的時候,有兩個途徑,一個是憑經驗微調,另外一個就是選擇不一樣大小的參數,帶入模型中,挑選表現最好的參數。html

  微調的一種方法是手工調製超參數,直到找到一個好的超參數組合,這麼作的話會很是冗長,你也可能沒有時間探索多種組合,因此可使用Scikit-Learn的GridSearchCV來作這項搜索工做。下面讓咱們一一探索。node

1,爲何叫網格搜索(GridSearchCV)?

  GridSearchCV的名字其實能夠拆分爲兩部分,GridSearch和CV,即網格搜索和交叉驗證。這兩個名字都很是好理解。網格搜索,搜索的是參數,即在指定的參數範圍內,按步長依次調整參數,利用調整的參數訓練學習器,從全部的參數中找到在驗證集上精度最高的參數,這實際上是一個訓練和比較的過程。git

  GridSearchCV能夠保證在指定的參數範圍內找到精度最高的參數,可是這也是網格搜索的缺陷所在,他要求遍歷全部可能參數的組合,在面對大數據集和多參數的狀況下,很是耗時。算法

 

2,什麼是Grid Search網格搜索?

  Grid Search:一種調參手段;窮舉搜索:在全部候選的參數選擇中,經過循環遍歷,嘗試每一種可能性,表現最好的參數就是最終的結果。其原理就像是在數組裏找到最大值。這種方法的主要缺點是比較耗時!bootstrap

  因此網格搜索適用於三四個(或者更少)的超參數(當超參數的數量增加時,網格搜索的計算複雜度會呈現指數增加,這時候則使用隨機搜索),用戶列出一個較小的超參數值域,這些超參數至於的笛卡爾積(排列組合)爲一組組超參數。網格搜索算法使用每組超參數訓練模型並挑選驗證集偏差最小的超參數組合。數組

2.1,以隨機森林爲例說明GridSearch網格搜索

  下面代碼,咱們要搜索兩種網格,一種是n_estimators,一種是max_features。GridSearch會挑選出最適合的超參數值。網絡

from sklearn.model_selection import GridSearchCV
param_grid = [
{'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
{'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
]

forest_reg = RandomForestRegressor()
grid_search = GridSearchCV(forest_reg, param_grid, cv=5,
                          scoring='neg_mean_squared_error')

grid_search.fit(housing_prepared, housing_labels)

  sklearn 根據param_grid的值,首先會評估3×4=12種n_estimators和max_features的組合方式,接下來在會在bootstrap=False的狀況下(默認該值爲True),評估2×3=6種12種n_estimators和max_features的組合方式,因此最終會有12+6=18種不一樣的超參數組合方式,而每一種組合方式要在訓練集上訓練5次, 因此一共要訓練18×5=90 次,當訓練結束後,你能夠經過best_params_得到最好的組合方式。多線程

grid_search.best_params_

  輸出結果以下:dom

{‘max_features’: 8, ‘n_estimators’: 30}

  獲得最好的模型:機器學習

grid_search.best_estimator_

  輸出以下:

RandomForestRegressor(bootstrap=True, criterion=‘mse’, max_depth=None,
max_features=8, max_leaf_nodes=None, min_impurity_decrease=0.0,
min_impurity_split=None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
n_estimators=30, n_jobs=1, oob_score=False, random_state=None,
verbose=0, warm_start=False)

  若是GridSearchCV初始化時,refit=True(默認的初始化值),在交叉驗證時,一旦發現最好的模型(estimator),將會在整個訓練集上從新訓練,這一般是一個好主意,由於使用更多的數據集會提高模型的性能。

  以上面有兩個參數的模型爲例,參數a有3中可能,參數b有4種可能,把全部可能性列出來,能夠表示成一個3*4的表格,其中每一個cell就是一個網格,循環過程就像是在每一個網格里遍歷,搜索,因此叫grid search。

 

2.2,以Xgboost爲例說明GridSearch網格搜索

  下面以阿里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)
#輸出最優訓練器的精度

  這裏關於網格搜索的幾個參數在說明一下,評分參數「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函數就好。

  這裏再貼一下經常使用的集成學習算法比較重要的須要調參的參數:

 

2.3,以SVR爲例說明GridSearch網格搜索

  以兩個參數的調優過程爲例:

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

iris_data = load_iris()
X_train,X_test,y_train,y_test = train_test_split(iris_data.data,iris_data.target,random_state=0)

# grid search start
best_score = 0
for gamma in [0.001,0.01,1,10,100]:
    for c in [0.001,0.01,1,10,100]:
        # 對於每種參數可能的組合,進行一次訓練
        svm = SVC(gamma=gamma,C=c)
        svm.fit(X_train,y_train)
        score = svm.score(X_test,y_test)
        # 找到表現最好的參數
        if score > best_score:
            best_score = score
            best_parameters = {'gamma':gamma,"C":c}

print('Best socre:{:.2f}'.format(best_score))
print('Best parameters:{}'.format(best_parameters))

  輸出結果:

Best socre:0.97
Best parameters:{'gamma': 0.001, 'C': 100}

  

2.4  上面調參存在的問題是什麼呢?

  原始數據集劃分紅訓練集和測試集之後,其中測試集除了用做調整參數,也用來測量模型的好壞;這樣作致使最終的評分結果比實際效果好。(由於測試集在調參過程當中,送到了模型裏,而咱們的目的是將訓練模型應用到unseen data上)。

2.5  解決方法是什麼呢?

  對訓練集再進行一次劃分,分爲訓練集和驗證集,這樣劃分的結果就是:原始數據劃分爲3份,分別爲:訓練集,驗證集和測試集;其中訓練集用來模型訓練,驗證集用來調整參數,而測試集用來衡量模型表現好壞。

  

  代碼:

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

iris_data = load_iris()
# X_train,X_test,y_train,y_test = train_test_split(iris_data.data,iris_data.target,random_state=0)
X_trainval,X_test,y_trainval,y_test = train_test_split(iris_data.data,iris_data.target,random_state=0)
X_train ,X_val,y_train,y_val = train_test_split(X_trainval,y_trainval,random_state=1)
# grid search start
best_score = 0
for gamma in [0.001,0.01,1,10,100]:
    for c in [0.001,0.01,1,10,100]:
        # 對於每種參數可能的組合,進行一次訓練
        svm = SVC(gamma=gamma,C=c)
        svm.fit(X_train,y_train)
        score = svm.score(X_val,y_val)
        # 找到表現最好的參數
        if score > best_score:
            best_score = score
            best_parameters = {'gamma':gamma,"C":c}

# 使用最佳參數,構建新的模型
svm = SVC(**best_parameters)

# 使用訓練集和驗證集進行訓練 more data always resultd in good performance
svm.fit(X_trainval,y_trainval)

# evalyation 模型評估
test_score = svm.score(X_test,y_test)

print('Best socre:{:.2f}'.format(best_score))
print('Best parameters:{}'.format(best_parameters))
print('Best score on test set:{:.2f}'.format(test_score))

  結果:

Best socre:0.96
Best parameters:{'gamma': 0.001, 'C': 10}
Best score on test set:0.92

  然而,這種簡潔的grid search方法,其最終的表現好壞與初始數據的劃分結果有很大的關係,爲了處理這種狀況,咱們採用交叉驗證的方式來減小偶然性。

 

2.6,交叉驗證改進SVM代碼(Grid Search with Cross Validation)

   代碼:

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split,cross_val_score

iris_data = load_iris()
# X_train,X_test,y_train,y_test = train_test_split(iris_data.data,iris_data.target,random_state=0)
X_trainval,X_test,y_trainval,y_test = train_test_split(iris_data.data,iris_data.target,random_state=0)
X_train ,X_val,y_train,y_val = train_test_split(X_trainval,y_trainval,random_state=1)
# grid search start
best_score = 0
for gamma in [0.001,0.01,1,10,100]:
    for c in [0.001,0.01,1,10,100]:
        # 對於每種參數可能的組合,進行一次訓練
        svm = SVC(gamma=gamma,C=c)
        # 5 折交叉驗證
        scores = cross_val_score(svm,X_trainval,y_trainval,cv=5)
        score = scores.mean()
        # 找到表現最好的參數
        if score > best_score:
            best_score = score
            best_parameters = {'gamma':gamma,"C":c}

# 使用最佳參數,構建新的模型
svm = SVC(**best_parameters)

# 使用訓練集和驗證集進行訓練 more data always resultd in good performance
svm.fit(X_trainval,y_trainval)

# evalyation 模型評估
test_score = svm.score(X_test,y_test)

print('Best socre:{:.2f}'.format(best_score))
print('Best parameters:{}'.format(best_parameters))
print('Best score on test set:{:.2f}'.format(test_score))

  結果:

Best socre:0.97
Best parameters:{'gamma': 0.01, 'C': 100}
Best score on test set:0.97

  交叉驗證常常與網絡搜索進行結合,做爲參數評價的一種方法,這種方法叫作grid search with cross validation。

  sklearn所以設計了一個這樣的類GridSearchCV,這個類實現fit,predict,score等方法。被當作一個estimator,使用fit方法,該過程當中:

  • (1) 搜索到最佳參數
  • (2)實例化了一個最佳參數的estimator

 

3,RandomizedSearchCV——(隨機搜索)

  文獻地址能夠參考:請點擊我

  所謂的模型配置,通常統稱爲模型的超參數(Hyperparameters),好比KNN算法中的K值,SVM中不一樣的核函數(Kernal)等。多數狀況下,超參數等選擇是無限的。在有限的時間內,除了能夠驗證人工預設幾種超參數組合之外,也能夠經過啓發式的搜索方法對超參數組合進行調優。稱這種啓發式的超參數搜索方法爲網格搜索。 

  咱們在搜索超參數的時候,若是超參數個數較少(三四個或者更少),那麼咱們能夠採用網格搜索,一種窮盡式的搜索方法。可是當超參數個數比較多的時候,咱們仍然採用網格搜索,那麼搜索所需時間將會指數級上升。

   因此有人就提出了隨機搜索的方法,隨機在超參數空間中搜索幾十幾百個點,其中就有可能有比較小的值。這種作法比上面稀疏化網格的作法快,並且實驗證實,隨機搜索法結果比稀疏網格法稍好。

  RandomizedSearchCV使用方法和類GridSearchCV 很類似,但他不是嘗試全部可能的組合,而是經過選擇每個超參數的一個隨機值的特定數量的隨機組合,這個方法有兩個優勢:

  • 若是你讓隨機搜索運行, 好比1000次,它會探索每一個超參數的1000個不一樣的值(而不是像網格搜索那樣,只搜索每一個超參數的幾個值)
  • 你能夠方便的經過設定搜索次數,控制超參數搜索的計算量。

  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_)

  建議使用隨機搜索。

 超參數搜索——網格搜索&並行搜索代碼

#-*- coding:utf-8 -*-

#1.使用單線程對文本分類的樸素貝葉斯模型的超參數組合執行網格搜索

from sklearn.datasets import fetch_20newsgroups
import numpy as np 
news = fetch_20newsgroups(subset='all')
from sklearn.cross_validation import train_test_split
#取前3000條新聞文本進行數據分割
X_train,X_test,y_train,y_test=train_test_split(news.data[:3000],
                                            news.target[:3000],test_size=0.25,random_state=33)


from sklearn.svm import SVC
from sklearn.feature_extraction.text import TfidfVectorizer
#*************導入pipeline*************
from sklearn.pipeline import Pipeline
#使用Pipeline簡化系統搭建流程,sklean提供的pipeline來將多個學習器組成流水線,一般流水線的形式爲: 
#將數據標準化的學習器---特徵提取的學習器---執行預測的學習器 
#將文本特徵與分類器模型串聯起來,[(),()]裏有兩個參數
#參數1:執行 vect = TfidfVectorizer(stop_words='english',analyzer='word')操做
#參數2:執行 svc = SVC()操做
clf = Pipeline([('vect',TfidfVectorizer(stop_words='english',analyzer='word')),('svc',SVC())])

#這裏須要試驗的2個超參數svc_gamma和svc_C的元素個數分別爲四、3,這樣咱們一共有12種超參數對集合
#numpy.linspace用於建立等差數列,numpy.logspace用於建立等比數列
#logspace中,開始點和結束點是10的冪
#例如logspace(-2,1,4)表示起始數字爲10^-2,結尾數字爲10^1即10,元素個數爲4的等比數列
#parameters變量裏面的key都有一個前綴,這個前綴其實就是在Pipeline中定義的操做名。兩者相結合,使咱們的代碼變得十分簡潔。
#還有注意的是,這裏對參數名是<兩條>下劃線 __
parameters = {'svc__gamma':np.logspace(-2,1,4),'svc__C':np.logspace(-1,1,3)}

#從sklearn.grid_search中導入網格搜索模塊GridSearchCV
from sklearn.grid_search import GridSearchCV
#GridSearchCV參數解釋:
#1.estimator : estimator(評估) object.
#2.param_grid : dict or list of dictionaries
#3.verbose:Controls the verbosity(冗餘度): the higher, the more messages.
#4.refit:default=True, Refit(再次擬合)the best estimator with the entire dataset
#5.cv : int, cross-validation generator 此處表示3折交叉驗證
gs = GridSearchCV(clf,parameters,verbose=2,refit=True,cv=3)

#執行單線程網格搜索
gs.fit(X_train,y_train)

print gs.best_params_,gs.best_score_

#最後輸出最佳模型在測試集上的準確性
print 'the accuracy of best model in test set is',gs.score(X_test,y_test) 

#小結:
#1.由輸出結果可知,使用單線程的網格搜索技術 對樸素貝葉斯模型在文本分類任務中的超參數組合進行調優,
#  共有12組超參數組合*3折交叉驗證 =36項獨立運行的計算任務
#2.在本機上,該過程一共運行了2.9min,尋找到最佳的超參數組合在測試集上達到的分類準確性爲82.27%

  

 

#2.使用多線程對文本分類的樸素貝葉斯模型的超參數組合執行網格搜索

#n_jobs=-1,表示使用該計算機的所有cpu
gs = GridSearchCV(clf,parameters,verbose=2,refit=True,cv=3,n_jobs=-1)
gs.fit(X_train,y_train)
print gs.best_params_,gs.best_score_
#輸出最佳模型在測試集上的準確性
print 'the accuracy of best model in test set is',gs.score(X_test,y_test) 

#小結:
#總任務相同的狀況下,使用並行搜索技術進行計算的話,執行時間只花費了1.1min;
#並且最終所得的的best_params_和score沒有發生變化,說明並行搜索能夠在不影響準確性的前提下,
#有效的利用計算機的CPU資源,大大節省了最佳超參數的搜索時間。

  

4, 超參數估計的隨機搜索和網格搜索的比較

  使用的數據集是小數據集 手寫數字數據集 load_digits() 分類   數據規模 5620*64

  (sklearn中的小數據能夠直接使用,大數據集在第一次使用的時候會自動下載)

  比較隨機森林超參數優化的隨機搜索和網格搜索。全部影響學習的參數都是同時搜索的(除了估計值的數量,它會形成時間/質量的權衡)。

  隨機搜索和網格搜索探索的是徹底相同的參數空間。參數設置的結果很是類似,而隨機搜索的運行時間要低的多。

  隨機搜索的性能稍差,不過這極可能是噪聲效應,不會延續到外置測試集

  注意:在實踐中,人們不會使用網格搜索同時搜索這麼多不一樣的參數,而是隻選擇那些被認爲最重要的參數。

  代碼以下:

#_*_coding:utf-8_*_
# 輸出文件開頭註釋的內容  __doc__的做用
'''
Python有個特性叫作文檔字符串,即DocString ,這個特性可讓你的程序文檔更加清晰易懂
'''
print(__doc__)
import numpy as np
from time import time
from scipy.stats import randint as sp_randint

from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier

# get some  data
digits = load_digits()
X, y = digits.data , digits.target

# build a classifier
clf = RandomForestClassifier(n_estimators=20)

# utility function to report best scores
def report(results, n_top= 3):
    for i in range(1, n_top + 1):
        candidates = np.flatnonzero(results['rank_test_score'] == i)
        for candidate in candidates:
            print("Model with rank:{0}".format(i))
            print("Mean validation score : {0:.3f} (std: {1:.3f})".
                  format(results['mean_test_score'][candidate],
                         results['std_test_score'][candidate]))
            print("Parameters: {0}".format(results['params'][candidate]))
            print("")

# 指定取樣的參數和分佈 specify parameters and distributions to sample from
param_dist = {"max_depth":[3,None],
              "max_features":sp_randint(1,11),
              "min_samples_split":sp_randint(2,11),
              "bootstrap":[True, False],
              "criterion":["gini","entropy"]
              }

# run randomized search
n_iter_search = 20
random_search = RandomizedSearchCV(clf,param_distributions=param_dist,
                                   n_iter=n_iter_search,cv =5)
start = time()
random_search.fit(X, y)
print("RandomizedSearchCV took %.2f seconds for %d candidates"
      " parameter settings." % ((time() - start), n_iter_search))
report(random_search.cv_results_)

# use a full grid over all parameters
param_grid = {"max_depth":[3,None],
              "max_features":[1, 3, 10],
              "min_samples_split":[2, 3, 10],
              "bootstrap":[True, False],
              "criterion":["gini","entropy"]
    }
# run grid search
grid_search = GridSearchCV(clf, param_grid=param_grid, cv =5)
start = time()
grid_search.fit(X , y)
print("GridSearchCV took %.2f seconds for %d candidate parameter settings."
      % (time() - start, len(grid_search.cv_results_['params'])))
report(grid_search.cv_results_)

  結果以下:

RandomizedSearchCV took 6.20 seconds for 20 candidates parameter settings.
Model with rank:1
Mean validation score : 0.930 (std: 0.031)
Parameters: {'bootstrap': False, 'criterion': 'entropy', 'max_depth': None, 'max_features': 6, 'min_samples_split': 5}

Model with rank:2
Mean validation score : 0.929 (std: 0.024)
Parameters: {'bootstrap': False, 'criterion': 'entropy', 'max_depth': None, 'max_features': 6, 'min_samples_split': 9}

Model with rank:3
Mean validation score : 0.924 (std: 0.020)
Parameters: {'bootstrap': False, 'criterion': 'gini', 'max_depth': None, 'max_features': 3, 'min_samples_split': 6}


Model with rank:1
Mean validation score : 0.932 (std: 0.023)
Parameters: {'bootstrap': False, 'criterion': 'gini', 'max_depth': None, 'max_features': 10, 'min_samples_split': 3}

Model with rank:2
Mean validation score : 0.931 (std: 0.014)
Parameters: {'bootstrap': False, 'criterion': 'gini', 'max_depth': None, 'max_features': 3, 'min_samples_split': 3}

Model with rank:3
Mean validation score : 0.929 (std: 0.021)
Parameters: {'bootstrap': False, 'criterion': 'entropy', 'max_depth': None, 'max_features': 3, 'min_samples_split': 2}

  

scikit-learn GridSearch庫概述

sklearn的Grid Search官網地址:請點擊我

1,GridSearchCV簡介

  GridSearchCV,它存在的意義就是自動調參,只要把參數輸進去,就能給出最優化結果和參數。可是這個方法適合於小數據集,一旦數據的量級上去了,很可貴到結果。這個時候就須要動腦筋了。數據量比較大的時候可使用一個快速調優的方法——座標降低。它實際上是一種貪心算法:拿當前對模型影響最大的參數調參,直到最優化;再拿下一個影響最大的參數調優,如此下去,直到全部的參數調整完畢。這個方法的缺點就是可能會跳到局部最優而不是全局最優,可是省時間省力,巨大的優點面前,仍是試一試,後續能夠再拿bagging再優化。

  一般算法不夠好,須要調試參數時必不可少。好比SVM的懲罰因子C,核函數kernel,gamma參數等,對於不一樣的數據使用不一樣的參數,結果效果可能差1~5個點,sklearn爲咱們專門調試參數的函數grid_search。

2,GridSearchCV參數說明

  參數以下:

class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, 
fit_params=None, n_jobs=None, iid=’warn’, refit=True, cv=’warn’, verbose=0, 
pre_dispatch=‘2*n_jobs’, error_score=’raise-deprecating’, return_train_score=’warn’)

  說明以下:

    1)estimator:選擇使用的分類器,而且傳入除須要肯定最佳的參數以外的其餘參數。每個分類器都須要一個scoring參數,或者score方法:如estimator = RandomForestClassifier(min_sample_split=100,min_samples_leaf = 20,max_depth = 8,max_features = 'sqrt' , random_state =10),

    2)param_grid:須要最優化的參數的取值,值爲字典或者列表,例如:param_grid = param_test1,param_test1 = {'n_estimators' : range(10,71,10)}

    3)scoring = None :模型評價標準,默認爲None,這時須要使用score函數;或者如scoring = 'roc_auc',根據所選模型不一樣,評價準則不一樣,字符串(函數名),或是可調用對象,須要其函數簽名,形如:scorer(estimator,X,y);若是是None,則使用estimator的偏差估計函數。

    4)fit_para,s = None

    5)n_jobs = 1 : n_jobs:並行數,int:個數,-1:跟CPU核數一致,1:默認值

    6)iid = True:iid:默認爲True,爲True時,默認爲各個樣本fold機率分佈一致,偏差估計爲全部樣本之和,而非各個fold的平均。

    7)refit = True :默認爲True,程序將會以交叉驗證訓練集獲得的最佳參數,從新對全部可能的訓練集與開發集進行,做爲最終用於性能評估的最佳模型參數。即在搜索參數結束後,用最佳參數結果再次fit一遍所有數據集。

    8)cv = None:交叉驗證參數,默認None,使用三折交叉驗證。指定fold數量,默認爲3,也能夠是yield訓練/測試數據的生成器。

    9)verbose = 0 ,scoring = None  verbose:日誌冗長度,int:冗長度,0:不輸出訓練過程,1:偶爾輸出,>1:對每一個子模型都輸出。

    10)pre_dispatch = '2*n_jobs' :指定總共發的並行任務數,當n_jobs大於1時候,數據將在每一個運行點進行復制,這可能致使OOM,而設置pre_dispatch參數,則能夠預先劃分總共的job數量,使數據最多被複制pre_dispatch次。

 

3,進行預測的經常使用方法和屬性

  • grid.fit()  :運行網格搜索
  • grid_scores_   :給出不一樣參數狀況下的評價結果
  • best_params_  :描述了已取得最佳結果的參數的組合
  • best_score_    :提供優化過程期間觀察到的最好的評分
  • cv_results_  :具體用法模型不一樣參數下交叉驗證的結果

4,GridSearchCV屬性說明

    (1) cv_results_ : dict of numpy (masked) ndarrays

    具備鍵做爲列標題和值做爲列的dict,能夠導入到DataFrame中。注意,「params」鍵用於存儲全部參數候選項的參數設置列表。

    (2) best_estimator_ : estimator

    經過搜索選擇的估計器,即在左側數據上給出最高分數(或指定的最小損失)的估計器。若是refit = False,則不可用。

    (3)best_score_ :float  best_estimator的分數

    (4)best_parmas_ : dict  在保存數據上給出最佳結果的參數設置

    (5) best_index_ : int 對應於最佳候選參數設置的索引(cv_results_數組)

    search.cv_results _ ['params'] [search.best_index_]中的dict給出了最佳模型的參數設置,給出了最高的平均分數(search.best_score_)。

    (6)scorer_ : function

    Scorer function used on the held out data to choose the best parameters for the model.

    (7)n_splits_ : int

    The number of cross-validation splits (folds/iterations).

 

3,利用決策樹預測乳腺癌的例子(網格搜索算法優化)

3.1 網格搜索算法與K折交叉驗證理論知識

  網格搜索算法是一種經過遍歷給定的參數組合來優化模型表現的方法。

  以決策樹爲例,當咱們肯定了要使用決策樹算法的時候,爲了可以更好地擬合和預測,咱們須要調整它的參數。在決策樹算法中,咱們一般選擇的參數是決策樹的最大深度。

  因而下面咱們會給出一系列的最大深度的值,好比{‘max_depth’:[1,2,3,4,5] },咱們就會盡量包含最優最大深度。

  不過咱們如何知道哪一個最大深度的模型是最好的呢?咱們須要一種可靠的評分方法,對每一個最大深度的決策樹模型都進行評價,這其中很是經典的一種方法就是交叉驗證,下面咱們就以K折交叉驗證爲例,詳細介紹一下其算法過程。

  首先咱們先看一下數據集時如何分割的,咱們拿到的原始數據集首先會按照必定的比例劃分出訓練集和測試集。好比下圖,以8:2分割的數據集:

  訓練集是用來訓練咱們的模型,它的做用就像咱們平時作的練習題;測試集用來評估咱們訓練好的模型表現如何,它不能被提早被模型看到。

  所以,在K折交叉驗證中,咱們用到的數據是訓練集中的全部數據,咱們將訓練集的全部數據平均劃分出K份(一般選擇K=10),取第K份做爲驗證集,它的做用就像咱們用來估計高考分數的模擬題,餘下的K-1份做爲交叉驗證的訓練集。

  對於咱們最開始選擇的決策樹的5個最大深度,以max_depth=1爲例,咱們先用第2-10份數據做爲訓練集訓練模型,用第一份數據做爲驗證集對此次訓練的模型進行評分,獲得第一個分數;而後從新構建一個max_depth = 1的決策樹,用第1和3-10份數據做爲訓練集訓練模型,用第2份數據做爲驗證集對此次訓練的模型進行評分,獲得第二個分數.....以此類推,最後構建一個max_depth = 1的決策樹用第1-9份數據做爲訓練集訓練模型,用第10份數據做爲驗證集對此次訓練的模型進行評分,獲得10個驗證分數,而後計算着10個驗證分數的平均分數,就是max_depth = 1的決策樹模型的最終驗證分數。

  對於max_depth = 2,3,4,5時,分別進行和max_depth =1 相同的交叉驗證過程,獲得他們的最終驗證分數,而後咱們就能夠對這5個最大深度的決策樹的最終驗證分數進行比較,分數最高的那個就是最優最大深度,咱們利用最優參數在所有訓練集上訓練一個新的模型,整個模型就是最優模型。

3.2 簡單的利用決策樹預測乳腺癌的例子

代碼:

from sklearn.model_selection import GridSearchCV,KFold,train_test_split
from sklearn.metrics import make_scorer , accuracy_score
from sklearn.tree  import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
import warnings
from sklearn.neighbors import KNeighborsClassifier as KNN

warnings.filterwarnings('ignore')

# load  data
data = load_breast_cancer()
print(data.data.shape)
print(data.target.shape)
# (569, 30)
# (569,)
X,y = data['data'] , data['target']

X_train,X_test,y_train,y_test = train_test_split(
    X,y,train_size=0.8 , random_state=0
)

regressor = DecisionTreeClassifier(random_state=0)
parameters = {'max_depth':range(1,6)}
scorin_fnc = make_scorer(accuracy_score)
kflod = KFold(n_splits=10)

grid = GridSearchCV(regressor,parameters,scorin_fnc,cv=kflod)
grid = grid.fit(X_train,y_train)
reg = grid.best_estimator_

print('best score:%f'%grid.best_score_)
print('best parameters:')
for key in parameters.keys():
    print('%s:%d'%(key,reg.get_params()[key]))

print('test score : %f'%reg.score(X_test,y_test))

# import pandas as pd
# pd.DataFrame(grid.cv_results_).T

# 引入KNN訓練方法
knn = KNN()
# 進行填充測試數據進行訓練
knn.fit(X_train,y_train)
params = knn.get_params()
score  = knn.score(X_test,y_test)
print("KNN 預測得分爲:%s"%score)

  結果:

(569, 30)
(569,)
best score:0.938462
best parameters:
max_depth:4
test score : 0.956140
KNN 預測得分爲:0.9385964912280702

  

問題一:AttributeError: 'GridSearchCV' object has no attribute 'grid_scores_'

問題描述:

  Python運行代碼的時候,到gsearch1.grid_scores_ 時報錯:

AttributeError: 'GridSearchCV' object has no attribute 'grid_scores_'

  

緣由:

  之因此出現以上問題,緣由在於grid_scores_在sklearn0.20版本中已被刪除,取而代之的是cv_results_。

解決方法:

  將下面代碼:

a,b,c = gsearch1.grid_scores_, gsearch1.best_params_, gsearch1.best_score_

  

  換成:

a,b,c = gsearch1.cv_results_, gsearch1.best_params_, gsearch1.best_score_

  

 

問題二:ModuleNotFoundError: No module named 'sklearn.grid_search'

問題描述:

  Python運行代碼時候,到from  sklearn.grid_search import GridSearchCV時報錯:

ModuleNotFoundError: No module named 'sklearn.grid_search'

  

緣由:

  sklearn.grid_search模塊在0.18版本中被棄用,它所支持的類轉移到model_selection 模板中。還要注意,新的CV迭代器的接口與這個模塊的接口不一樣,sklearn.grid_search在0.20中被刪除。

解決方法:

  將下面代碼

from sklearn.grid_search import GridSearchCV

  修改爲:

from sklearn.model_selection import GridSearchCV

  

參考文獻:https://blog.51cto.com/emily18/2088128

https://blog.csdn.net/jh1137921986/article/details/79827945

https://blog.csdn.net/juezhanangle/article/details/80051256

相關文章
相關標籤/搜索