K折交叉驗證與網格搜索算法(scikit learn)

K折交叉驗證
過程:

選擇K的值(一般是10),將數據集分成不重疊的K等份 。
使用其中的K-1份數據作爲訓練數據,另外一份數據作爲測試數據,進行模型的訓練
使用一種度量測度來衡量模型的預測性能
優點:

可通過降低模型在一次數據分割中性能表現上的方差來保證模型性能的穩定性
可用於進行參數調節、模型性能比較、特徵選擇等
缺點:
交叉驗證帶來一定的計算代價, 是當數據集很大的時候,計算過程會變得很慢
訓練集用來訓練我們的模型;測試集用來評估我們訓練好的模型表現如何,在進行測試前要絕對保密不能提前被模型看到的。

在K折交叉驗證中,我們用到的數據是訓練集中的所有數據。我們將訓練集的所有數據平均劃分成K份(通常選擇K=10),取第K份作爲驗證集,餘下的K-1份作爲交叉驗證的訓練集。

網格搜索算法
網格搜索算法是一種一種調參手段,通過遍歷給定參數組合來優化模型表現的方法。其原理就像是在數組裏找最大值。
以決策樹爲例,當確定了要使用決策樹算法的時候,爲了能夠更好地擬合和預測,需要調整它的參數。在決策樹算法中,我們通常選擇的參數是決策樹的最大深度。

於是我們會給出一系列的最大深度的值,比如 {‘max_depth’: [1,2,3,4,5,6]},我們會儘可能包含最優最大深度。

爲了知道哪一個最大深度的模型是最好的,需要一種可靠的評分方法,對每個最大深度的決策樹模型都進行評分,這其中非常經典的一種方法就是上述所述的交叉驗證。
準備數據(鳶尾花數據集)及導入相關python庫

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.model_selection import cross_val_score
    iris = load_iris()
    X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=0)
    print("Size of training set:{} size of testing set:{}".format(X_train.shape[0], X_test.shape[0]))

1
2
3
4
5
6
7
8
簡單的網格搜索,使用for循環遍歷

def simpleGridSearch(X_train, X_test, y_train, y_test):
    '''
    使用for循環實現網格搜索
    :param X_train:
    :param X_test:
    :param y_train:
    :param y_test:
    :return:
    '''
    # grid search start
    best_score = 0
    for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
        for C in [0.001, 0.01, 0.1, 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 score:{:.2f}".format(best_score))
    print("Best parameters:{}".format(best_parameters))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
結果:

Size of training set:112 size of testing set:38
Best score:0.97
Best parameters:{'gamma': 0.001, 'C': 100}

1
2
3
4
上述方法存在的問題:
原始數據集劃分成訓練集和測試集以後,其中測試集除了用作調整參數,也用來測量模型的好壞;這樣做導致最終的評分結果比實際效果要好。因爲測試集在調參過程中,送到了模型裏,而我們的目的是將訓練模型應用在未知數據上。

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

使用交叉驗證python代碼如下:

def gridSearchCv(X_train, X_test, y_train, y_test):
    '''
    使用for循環實現網格搜索與交叉驗證
    :param X_train:
    :param X_test:
    :param y_train:
    :param y_test:
    :return:
    '''
    best_score = 0.0
    for gamma in [0.001,0.01,0.1,1,10,100]:
        for C in [0.001,0.01,0.1,1,10,100]:
            svm = SVC(gamma=gamma, C=C)
            scores = cross_val_score(svm, X_train, y_train, cv=5) #5折交叉驗證
            score = scores.mean() #取平均數
            if score > best_score:
                best_score = score
                best_parameters = {"gamma": gamma, "C": C}
    svm = SVC(**best_parameters)
    svm.fit(X_train, y_train)
    test_score = svm.score(X_test,y_test)
    print("Best score on validation set:{:.2f}".format(best_score))
    print("Best parameters:{}".format(best_parameters))
    print("Score on testing set:{:.2f}".format(test_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
結果:

Size of training set:112 size of testing set:38
Best score on validation set:0.97
Best parameters:{'C': 100, 'gamma': 0.01}
Score on testing set:0.97
1
2
3
4
這樣對模型的度量會更準確。

GridSearchCV
交叉驗證與網格搜索進行結合,作爲參數評價的一種方法,叫做grid search with cross validation。scikit learn中設計了一個這樣的類GridSearchCV,這個類實現了fit,predict,score等方法,被當做了一個estimator,使用fit方法,該過程中:(1)搜索到最佳參數;(2)實例化了一個最佳參數的estimator;實際上,該過程代替了進行參數搜索時的for循環過程。


def skGridSearchCv(X_train, X_test, y_train, y_test):
    '''
    利用sklearn中的GridSearchCV類
    :param X_train:
    :param X_test:
    :param y_train:
    :param y_test:
    :return:
    '''
    #把要調整的參數以及其候選值 列出來;
    param_grid = {"gamma": [0.001,0.01,0.1,1,10,100],
                 "C": [0.001,0.01,0.1,1,10,100]}
    print("Parameters:{}".format(param_grid))

    grid_search = GridSearchCV(SVC(),param_grid,cv=5) # 實例化一個GridSearchCV類
    grid_search.fit(X_train, y_train)  # 訓練,找到最優的參數,同時使用最優的參數實例化一個新的SVC estimator。
    print("Test set score:{:.2f}".format(grid_search.score(X_test, y_test)))
    print("Best parameters:{}".format(grid_search.best_params_))
    print("Best score on train set:{:.2f}".format(grid_search.best_score_))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
結果

Parameters:{'C': [0.001, 0.01, 0.1, 1, 10, 100], 'gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
Test set score:0.97
Best parameters:{'C': 10, 'gamma': 0.1}
Best score on train set:0.98
1
2
3
4
Grid Search 調參方法存在的缺點:
耗時。參數越多,候選值越多,耗費時間越長!
一般情況下,先定一個大範圍,然後再細化調參。

完整代碼:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = 'WF'

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


def simpleGridSearch(X_train, X_test, y_train, y_test):
    '''
    使用for循環實現網格搜索
    :param X_train:
    :param X_test:
    :param y_train:
    :param y_test:
    :return:
    '''
    # grid search start
    best_score = 0
    for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
        for C in [0.001, 0.01, 0.1, 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 score:{:.2f}".format(best_score))
    print("Best parameters:{}".format(best_parameters))


def gridSearchCv(X_train, X_test, y_train, y_test):
    '''
    使用for循環實現網格搜索與交叉驗證
    :param X_train:
    :param X_test:
    :param y_train:
    :param y_test:
    :return:
    '''
    best_score = 0.0
    for gamma in [0.001,0.01,0.1,1,10,100]:
        for C in [0.001,0.01,0.1,1,10,100]:
            svm = SVC(gamma=gamma, C=C)
            scores = cross_val_score(svm, X_train, y_train, cv=5) #5折交叉驗證
            score = scores.mean() #取平均數
            if score > best_score:
                best_score = score
                best_parameters = {"gamma": gamma, "C": C}
    svm = SVC(**best_parameters)
    svm.fit(X_train, y_train)
    test_score = svm.score(X_test,y_test)
    print("Best score on validation set:{:.2f}".format(best_score))
    print("Best parameters:{}".format(best_parameters))
    print("Score on testing set:{:.2f}".format(test_score))


def skGridSearchCv(X_train, X_test, y_train, y_test):
    '''
    利用sklearn中的GridSearchCV類
    :param X_train:
    :param X_test:
    :param y_train:
    :param y_test:
    :return:
    '''
    #把要調整的參數以及其候選值 列出來;
    param_grid = {"gamma": [0.001,0.01,0.1,1,10,100],
                 "C": [0.001,0.01,0.1,1,10,100]}
    print("Parameters:{}".format(param_grid))

    grid_search = GridSearchCV(SVC(),param_grid,cv=5) # 實例化一個GridSearchCV類
    X_train, X_test, y_train, y_test = train_test_split(iris.data,iris.target, random_state=10)
    grid_search.fit(X_train, y_train)  # 訓練,找到最優的參數,同時使用最優的參數實例化一個新的SVC estimator。
    print("Test set score:{:.2f}".format(grid_search.score(X_test, y_test)))
    print("Best parameters:{}".format(grid_search.best_params_))
    print("Best score on train set:{:.2f}".format(grid_search.best_score_))


if __name__ == '__main__':
    iris = load_iris()
    X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=0)
    print("Size of training set:{} size of testing set:{}".format(X_train.shape[0], X_test.shape[0]))
    # simpleGridSearch(X_train, X_test, y_train, y_test)
    # gridSearchCv(X_train, X_test, y_train, y_test)
    skGridSearchCv(X_train, X_test, y_train, y_test)
--------------------- 
作者:wf592523813 
來源:CSDN 
原文:https://blog.csdn.net/wf592523813/article/details/86309547 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

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