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 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/qq_33374294/article/details/89005146