模型评估和验证【2】——交叉验证、网格搜索与模型评估

标签: 模型评估和验证【2】——交叉验证与模型评估

2.模型评估方法之数据集划分

在机器学习任务中,拿到数据后,我们首先会将原始数据集分为三部分:训练集、验证集和测试集。 
训练集用于训练模型,验证集用于模型的参数选择配置,测试集对于模型来说是未知数据,用于评估模型的泛化能力。

在使用机器学习的时候,往往会有;验证集与测试集,他们的作用不同。

区分验证集,与测试集。

 

注:

Validation(验证集)可选-----参与模型训练过程,对不同模型参数的结果进行交叉验证,选择模型的最优超参数

Test(测试集) 可选----用于独立评估模型的泛化能力,绝对不参与模型训练

 如何从数据中抽取验证集与测试集?

在Scikit-learn中有封装好的模块,来实现数据集划分。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test =train_test_split(datasets_X, datasets_y, test_size=0.3,random_state=0)

简单的验证,这种验证具有偶然性,利用平均的思想来减少模型评估的误差。还有一点需要注意,交叉验证时所使用的数据只在划分数据之后的train_x中,进行二次分解,这点需要理解的,那么问题来了,什么是交叉验证?


什么是交叉验证法?

它的基本思想就是将原始数据(dataset)进行分组,一部分做为训练集来训练模型,另一部分做为测试集来评价模型。

为什么用交叉验证法?

  1. 交叉验证用于评估模型的预测性能,尤其是训练好的模型在新数据上的表现,可以在一定程度上减小过拟合。
  2. 还可以从有限的数据中获取尽可能多的有效信息。

k 一般取 10, 
数据量小的时候,k 可以设大一点,这样训练集占整体比例就比较大,不过同时训练的模型个数也增多。 
数据量大的时候,k 可以设小一点。

使用交叉验证的最简单的方法是调用cross_val_score,下面的例子演示了如何估算一个线性的准确性.

>>> 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)
>>> scores                                              
array([ 0.96...,  1.  ...,  0.96...,  0.96...,  1.        ])

>>> print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
Accuracy: 0.98 (+/- 0.03)

默认情况下,score在每次CV中计算的分数都是模型默认的score方法,我们可以通过使用scoring参数来改变模型的评估准则。(By default, the score computed at each CV iteration is the score method of the estimator. It is possible to change this by using the scoring parameter:)。

>>> from sklearn import metrics
>>> scores = cross_val_score(
...     clf, iris.data, iris.target, cv=5, scoring='f1_macro')
>>> scores                                              
array([ 0.96...,  1.  ...,  0.96...,  0.96...,  1.        ])

See The scoring parameter: defining model evaluation rules for details. 

交叉验证与网格搜索的联系 

       交叉验证与网格搜索是机器学习中的两个非常重要且基本的概念,但是这两个概念在刚入门的时候并不是非常容易理解与掌握,自己开始学习的时候,对这两个概念理解的并不到位,主要是他们的区别与联系,下面总结一下自己对这两个概念的一些感受,也许不是那么的正确,如有错误,还望留言交流,以便更正我的错误观点。

1)从交叉验证得到的结果可以看出(如上的实例),模型只是给出了对应模型的得分,好像并不能从中直接看出有多么 大的用途(个人意见)

2)那我就有点奇怪,那如果只是能获得模型对预测的得分,这有什么用呢,这是我以前比较困惑的问题?

3)回归问题本身,我们很多时候都是做的预测/分类问题,那么我们当然希望我们的模型在训练完后,对未知数据的预测能力也比较强,这就自然而然要调整模型参数啦,课问题是,有什么方法能让我们获的一个相对较优的参数呢, 有的,那就是网格搜索grid_search,用简答的话来说就是你手动的给出一个模型中你想要改动的所用的参数,程序自动的帮你使用穷举法来将所用的参数都运行一遍,通过得分最高来判断模型的好坏,什么得分最高,是的,得分,好像我上面谈到的交叉验证就能获得得分呀,暂且先放在这里,瞎说一下

4)有得分,那自然就得有评分准则,根据问题种类的不同,我们也会有相对应的评分准则来衡量一下这个模型到底怎么样。根据实际情况来确定的可能是accuracy、f1-score、pricise、r2等

5)好了,铺垫了这么多,终于要说重点了,我都觉的自己怎么这么的能扯,有了好的评分方式,但是只用一次的结果就能说明某组的参数组合比另外的参数组合好吗?这显然是不严谨的,从初中到高中再到大学,我们都一直被灌输偶然误差,系统误差不是,这里就体现了交叉验证的多次验证再取平均,来降低偶然误差的影响,所以将交叉验证与参数调优相整合联系在一起后,仿佛就是天生为网格搜索做的准备呀。

网格搜索一般是针对参数进行寻优,交叉验证是为了验证训练模型拟合程度。两者常常结合在一起用,但我们用的更多的当然是网格搜索啦,因为我们的目的常常都是找出更优的模型参数,单独的应用交叉验证的场景有,但应用的不多。

还有一个主意点:

我们在做交叉验证时,不是用到了

X_train, X_test, y_train, y_test =train_test_split(datasets_X, datasets_y, test_size=0.3,random_state=0)函数进行分割训练集和测试集吗,如果你要使用网格搜索的话,训练的时候,其实是可以直接使用datasets_X, datasets_y来做训练的, 因为模型在训练的时候,就已经自己做了切分

下面的例子,你会立马感受到这两者的区别

网格搜索内部嵌套了交叉验证(自己手工实现参数调优)

import numpy as np
from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
iris = load_iris()
X_trainval, X_test, y_trainval, y_test = train_test_split(iris.data, iris.target, random_state=0)   #总集——>训练验证集+测试集
X_train, X_valid, y_train, y_valid = train_test_split(X_trainval, y_trainval, random_state=1)   #训练验证集——>训练集+验证集
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)
        scores = cross_val_score(svm, X_trainval, y_trainval, cv=5)   #在训练集和验证集上进行交叉验证
        score = np.mean(scores)   # compute mean cross-validation accuracy
        if score > best_score:   
            best_score = score
            best_parameters = {'C': C, 'gamma': gamma}

# rebuild a model on the combined training and validation set
print('网格搜索for循环<有cross_val_score交叉验证>获得的最好参数组合:',best_parameters)
print(' ')
svmf = SVC(**best_parameters)
svmf.fit(X_trainval, y_trainval)
print('网格搜索<有交叉验证>获得的最好估计器,在训练验证集上没做交叉验证的得分:',svmf.score(X_trainval,y_trainval))#####
print(' ')
scores = cross_val_score(svmf, X_trainval, y_trainval, cv=5)   #在训练集和验证集上进行交叉验证   
print('网格搜索<有交叉验证>获得的最好估计器,在训练验证集上做交叉验证的平均得分:',np.mean(scores))   #交叉验证的平均accuracy   
print(' ')
print('网格搜索<有交叉验证>获得的最好估计器,在测试集上的得分:',svmf.score(X_test,y_test))#####
# print(' ')
# print(' ')
# scoreall = cross_val_score(svmf, iris.data, iris.target, cv=5)  
# print(scoreall ,np.mean(scoreall)) 

        是不是觉得这个参数调优好复杂的样子,尽管代码的原理很简单,但相比下面的调库来实现参数调优,就显得很复杂了,不信咋们来看

from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn import metrics
from sklearn.svm import SVC


param_grid={'gamma':thresholds}
clf=GridSearchCV(SVC(kernel='rbf'),param_grid,cv=5)
clf.fit(X_trainval, y_trainval)

print("最佳效果:%0.3f"% clf.best_score_)
print("最优参数组合:")
best_parameters=clf.best_estimator_.get_params()
for param_name in sorted(param_grid.keys()):
    print('\t%s:%r' %(param_name,best_parameters[param_name]))

是吧,没有对比就没有伤害。

 

3.模型评估指标

3.1分类模型的评估指标

评估一个分类器,通常比评估一个回归器更加玄学。所以我们将会花大量的篇幅在这个话题上。有许多量度性能的方法。

  • 误分类矩阵
  • 准确率(Precision)
  • 召回率(Recall)
  • F1分数
  • AUC
  • ROC

基于混淆矩阵的评估度量

混淆矩阵赋予一个分类器性能表现更全面的认识,同时它通过计算各种分类度量,指导你进行模型选择。

正确率(Accuracy)”陷阱

• 如果训练样本中正例占比非常少:正例100个(1%),反例9900个(99%),你要特别注意!
• 这类问题叫样本类别不平衡问题

       提出confusion_matrics的原因是因为利用正确率来衡量模型分类的置信度时会出错,(出现这类问题是常常在不平衡的样本中)所以提出了混肴矩阵。

  • 真阳性(True Positive,TP):指被分类器正确分类的正例数据
  • 真阴性(True Negative,TN):指被分类器正确分类的负例数据
  • 假阳性(False Positive,FP):被错误地标记为正例数据的负例数据
  • 假阴性(False Negative,FN):被错误地标记为负例数据的正例数据

一般来说:准确率高时召回率就低;而召回率高时准确率就低

F1分数,又称平衡F分数,它被定义为准确率和召回率的调和平均数,用它来综合评估模型性能

调和平均数:

ROC曲线和AUC

      ROC(Receiver Operating Characteristic,接受者工作特征曲线)曲线和AUC常被用来评价一个二值分类器(binary classifier)的优劣。

       很多学习器是为测试样本产生一个实值或概率预测,然后将这个预测值与一个分类阈值进行比较,若大于阈值则分为正类,否则为反类。例如,神经网络在一般情形下是对每个测试样本预测出一个[0.0,1.0]之间的实值,然后将这个值与阈值0.5进行比较,大于0.5则判为正例,否则为反例。这个阈值设置的好坏,直接决定了学习器的泛化能力。因此,阈值设置的好坏,体现了综合考虑学习器在不同任务下的泛化性能的好坏。为了形象的描述这一变化,在此引入ROC曲线,ROC曲线则是从阈值选取角度出发来研究学习器泛化性能的有力工具。

ROC曲线:受试者工作特性曲线(Receiver Operating Characteristic Curve)。横轴是假正例率(False Positive Rate, fpr),纵轴是真正例率(True Positive Rate, tpr)。

横轴:FPR = FP / (TN + FP):负样本中预测为正样本的比例。分母就是负样本的数量。 
纵轴:TPR = TP / (TP + FN):正样本中预测为正样本的比例,其实就是recall。分母就是正样本的数量。

ROC的评判标准:

1.若一个分类器的ROC曲线被另一个分类器的ROC曲线完全“包住”,则后者性能优于前者 
2.若两个分类器的ROC曲线发生交叉,则难以一般性地断言两者孰优孰劣。如果一定要进行比较,可以比较AUC大小。

       AUC是现在分类模型,特别是二分类模型使用的主要离线评测指标之一。相比于准确率、召回率、F1等指标,AUC有一个独特的优势,就是不关注具体得分,只关注排序结果,这使得它特别适用于排序问题的效果评估,例如推荐排序的评估。AUC这个指标有两种解释方法,一种是传统的“曲线下面积”解释,另一种是关于排序能力的解释。例如0.7的AUC,其含义可以大概理解为:给定一个正样本和一个负样本,在70%的情况下,模型对正样本的打分高于对负样本的打分。可以看出在这个解释下,我们关心的只有正负样本之间的分数高低,而具体的分值则无关紧要。

3.2 回归模型的评估指标

      对于分类问题,评价测度是准确率,但这种方法不适用于回归问题,我们使用针对连续数值的评价指标。这里介绍3种常用的针对回归问题的评价指标。

1)平均绝对误差(Mean Absolute Error,MAE)

2) 均方误差(Mean Squared Error,MSE)

3) 均方根误差(Root Mean Squared Error,RMSE)

demo:以均方根误差为例

import numpy as np
sum_mean = 0
for i in range(len(y_pre)):
    sum_mean+=(y_pre[i]-y_test.values[I])**2
print("RMSE:",np.sqrt(sum_mean/len(y_pre))

 

参考资料:

http://scikit-learn.org/stable/modules/cross_validation.html#cross-validation

 

原文链接:加载失败,请重新获取