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

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

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

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

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

  GridSearchCV可以保證在指定的參數範圍內找到精度最高的參數,但是這也是網格搜索的缺陷所在,他要求遍歷所有可能參數的組合,在面對大數據集和多參數的情況下,非常耗時。

 

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

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

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

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

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

1

2

3

4

5

6

7

8

9

10

11

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_獲得最好的組合方式。

1

grid_search.best_params_

  輸出結果如下:

1

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

  得到最好的模型:

1

grid_search.best_estimator_

  輸出如下:

1

2

3

4

5

6

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的使用方法。(此小例的代碼是參考這裏:請點擊我

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

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是允許我們自定義的,但是需要注意格式。

  接下來看一下我們定義的評價函數:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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網格搜索

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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

  輸出結果:

1

2

Best socre:0.97

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

  

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

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

2.5  解決方法是什麼呢?

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

  

  代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

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

  結果:

1

2

3

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)

   代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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

  結果:

1

2

3

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參數,同樣的給出代碼。

   代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

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

  建議使用隨機搜索。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

#-*- 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的元素個數分別爲4、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%

  

 

1

2

3

4

5

6

7

8

9

10

11

12

13

#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中的小數據可以直接使用,大數據集在第一次使用的時候會自動下載)

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

  隨機搜索和網格搜索探索的是完全相同的參數空間。參數設置的結果非常相似,而隨機搜索的運行時間要低的多。

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

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

  代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

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

  結果如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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參數說明

  參數如下:

1

2

3

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 簡單的利用決策樹預測乳腺癌的例子

代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

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)

  結果:

1

2

3

4

5

6

7

(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_ 時報錯:

1

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

  

原因:

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

解決方法:

  將下面代碼:

1

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

  

  換成:

1

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時報錯:

1

ModuleNotFoundError: No module named 'sklearn.grid_search'

  

原因:

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

解決方法:

  將下面代碼

1

from sklearn.grid_search import GridSearchCV

  修改成:

1

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

不經一番徹骨寒 怎得梅花撲鼻香

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章