sklearn之Cross-validation、GridSearchCV,以及训练集(train)、测试集(test)、验证集(validate)的辨析

1.训练集(train)、测试集(test)、验证集(validate)

对于初学者而言,训练集、测试集、验证集这三个词可能会让你很迷糊,特别是后两者。这里我尽量用简单的话说一下我自己的理解,希望可以讲明白:

        对于机器学习模型训练而言,一般是分为训练集和测试集的。训练集有input(X)和label(y),测试集只有input(X),它的label是要测试集训练好的模型去预测的。

        那么验证集是怎么回事?验证集从两个角度来说——

(1)首先,从它做的事情的角度来说,它也是给出其input(X),然后让训练集训练好的model去predict验证集的label(我们称y_predict)。所有从这个作用的角度而言验证集和测试集类似,都是拿train出来的model去预测得到结果。

(2)其次,从它的“成分”来看,它是属于训练集的,也就是说,验证集其实是训练集的一个子集。所以根据前面所述,验证集我们预测得到y_predict之后,其实它本身就有实际真实的label(y),这样就可以让我们去通过对y_predict和真实值y进行比较来对这个模型的预测能力(泛化能力)进行评价,避免了只在训练集上表现出色、在测试集上表现一般的“过拟合”问题

        举个小例子来说明一下训练集、测试集、验证集这哥仨:

        假设小驴一梦回到天真烂漫的高中时代,要面临月考了。此时月考试题就是“测试集”。我为了能在这个“测试集”上取得好成绩,所以当然要多做题,然后对答案。这些带有答案的练习题,就是“训练集”,是小驴用于提升自己习得某科知识能力的习题。但仅仅做题看答案是没用的,因为你也不知道你在考试的情况下会发挥如何,所以小驴把一部分有答案的习题拿出来,先不看答案做一遍,这一部分习题就是“验证集”。做完自我测验的小驴拿着自己答案去和标准答案进行对照并打分,得到的分数,就可以在一定程度上反映小驴的学习水平如何,此时,我们可以把小驴看做一个经过train的“模型”

2.Cross-validation——交叉验证:

        接着上面的说。小驴如果害怕自己所选的“验证集”自我测验习题有失偏颇,比如对于物理,全都是能量守恒的题目却没有牛顿第二定律的内容,而自己刚好擅长能量守恒导致自己的自测分数“虚高”,那么应该怎么做呢?

        很简单,大家肯定也猜到了,那就是,在我们无法左右习题是否偏颇的情况下,我们只能让小驴在多个不同的习题集上自测,然后取自测的平均分。但在习题总量有限的情况下,小驴该怎么做才能最客观的反映自己的学习能力呢?

        我们再假设,小驴是一个可以穿梭时空的人(好吧小驴就是这么神奇呵呵呵)。我们现在把所有有答案的习题(所有测试集)分成10份。第一次小驴拿前9份作为“训练集”来训练自己,然后用第10份作为“验证集”来自测分数,得到score1;第二次小驴时空倒转回到做过习题之前的那个自己(所有习题全部忘记),再拿除了第9份的9份习题做“训练集”习题,然后用第9份作为“验证集”自测,得到score2,并以此类推,得到10个分数。10个分数取平均,得到最终的平均分,作为小驴学习能力的最客观体现。现在,小驴的班级里有小马,小猪,小狼这些同学,他们也用这种方式得到其“学习能力的客观体现”,最终我们就可以通过这个指标,在考试前,就知道谁学习能力更强。(当然是小驴咯哈哈哈)

 

        有了小驴的例子,我们就可以自然而然的引出交叉验证的概念:我们将训练集分成k份,每次取(k-1)份用于训练model,1份用于验证(或言之:测试),再通过某种metric进行打分;然后再选择不同的(k-1)份重新训练model,1份用于对该model进行验证,再通过某种metric进行打分....。最终,我们得到了k个分数,取平均,我们就可以知道这个model的分数了。

        我们使用Cross-validation,多用于对模型参数(即超参数。普通参数model会自己习得,比如线性模型中的θ每个特征的权重)的选择。此时,选用不同超参的模型,可看作“不同的estimator”,然后我们用交叉验证对这个estimator打平均分,从而通过这个平均分对estimator的超参数进行选择。

3.sklearn.model_selection中的CV:

   cross_val_scorecross_validate二者均用于交叉验证,返回值就是scores(每次交叉验证的得分,list形式)。你设置cv =k,就返回长度为k个scores组成的list。具体使用代码如下: 

cross_val_score:

>>> from sklearn import metrics
>>> from sklearn.model_selection import cross_val_score

>>> clf = svm.SVC(kernel='linear', C=1)
>>> scores = cross_val_score(
...     clf, iris.data, iris.target, cv=5, scoring='f1_macro')
>>> scores                                              
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

如上所示,我们对SVM分类器当超参数C=1时的这个model进行交叉验证,看其得分。

clf:数据集要去fit的estimator

iris.data, iris.target:训练集的input(X)和其label(y)

cv=5:5折交叉验证。最终scores也是个长度为5的list

scoring='f1_macro':评价标准metrics.详见链接:Metrics 、scoring-parameters

cross_validate:

>>> from sklearn.model_selection import cross_validate
>>> from sklearn.metrics import recall_score

>>> scoring = ['precision_macro', 'recall_macro']                         #多个评价指标
>>> clf = svm.SVC(kernel='linear', C=1, random_state=0)
>>> scores = cross_validate(clf, iris.data, iris.target, scoring=scoring,
...                         cv=5, return_train_score=False)
>>> sorted(scores.keys())
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']
>>> scores['test_recall_macro']                       
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

 cross_validate和cross_val_score的区别在于以下两点

  1. 允许传入多个metrics作为评价指标
  2. 它的返回值是个dict而非list,内容包括5类:test_score, train_score, fit_time, score_times, training scores ,(fitted) estimators,它们分别是:验证集得分、训练集得分、每一折cv的estimator fit训练集的时间、每一折cv的estimator对验证集打分的时间、每一折cv的estimator对象。其中后两类的返回与否是可以选择的(见下)。

return_train_score=boolean:决定是否计算并返回训练集(而非验证集)的得分。训练集的得分可以让我们在和验证集得分的对比中进行偏差/过拟合的取舍。返回每个训练集得分是个计算量较大,而且对你选择泛化能力最佳的estimator无用的。

return_estimator = boolean:和上面类似,是否在return中包含“estimators”

scoring=scoring:这里把两种打分方式组成list传入cross_validate函数中

值得注意的事情

对于scoring参数只传入一个打分标准的,且scoring=string, callable or None,Return的dict的keys为:['test_score', 'fit_time', 'score_time']

对于scoring参数传入多个打分标准的,Return的dict的keys为:['test_', 'test_', 'test_', 'fit_time', 'score_time'] 

4.Grid Search:给模型寻找最佳超参数

        sklearn.model_selection.GridSearchCV和交叉验证是相辅相成的。因为GridSearchCV本身就是利用交叉验证的方法穷举地搜索交叉验证得分最佳的超参数组合。GridSearchCV之所以称为“GridSearch”即格点搜索,实际上是因为几种超参数的组合就形如网格的格点一样,这里还是用SVC的超参数C和sigma举例:

	    0.01	    0.1	      1.0	    10.0	    100.0
1	(0.01, 1)	(0.1, 1)	(1, 1)	  (10, 1)     (100, 1)
2	(0.01, 2)	(0.1, 2)	(1, 2)	  (10, 2)	 (100, 2)
3	(0.01, 3)	(0.1, 3)	(1, 3)    (10, 3)	 (100, 3)
4	(0.01, 4)	(0.1, 4)	(1, 4)	  (10, 4)	 (100, 4)
5	(0.01, 5)	(0.1, 5)	(1, 5) 	  (10, 5)	 (100, 5)
# 行为C的取值,列为sigma取值

        如上所示,C和sigma的取值组成了一个5*5的网格,每个格点均是一组超参数,而每组超参都能确定一个estimator。GridSearchCV对其中每组超参数所确定的estimator均进行交叉验证,并且选择交叉验证得分最佳的超参数组合。

 具体代码如下:

import numpy as np
from sklearn import svm
from sklearn.model_selection import GridSearchCV

model = svm.SVR(kernel='rbf')
c_can = np.logspace(-2, 2, 10)
gamma_can = np.logspace(-2, 2, 10)
svr = GridSearchCV(model, param_grid={'C': c_can, 'gamma': gamma_can}, cv=5)

重要属性及方法:

cv_results_:旧版本是“grid_scores_”,cv_results_是详尽、升级版。内容较好理解,包含了'mean_test_score'(验证集平均得分),'rank_test_score'(验证集得分排名),'params'(dict形式存储所有待选params的组合),甚至还有在每次划分的交叉验证中的得分('split0_test_score'、 'split1_test_score'等),就是输出的内容稍显臃肿。内容以dict形式输出,我们可以转成DataFrame形式,看起来稍微养眼一点。

best_params_ : dict:最佳参数组合

best_score_ : float:cv_results_属性中,'mean_test_score'里面的最高分。即你验证集得到的最高分数

best_estimator_ : estimator or dict:得到打分最高的超参组合对应的estimator

fit()/predict():用网格搜索得到的最佳超参所构建的estimator对数据集进行fit、predict

get_params():这个和‘best_estimator_ ’这个属性相似,但可以得到这个模型更多的参数

 欢迎转载,转载请务必注明出处,多谢!

你可能感兴趣的:(机器学习,sklearn,调参,概念,Python)