版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第6章模型评估及改进6.1交叉验证6.2网格搜索6.3评估指标6.4小结6.1交叉验证
对于给定的数据来说,我们无法知道哪些数据是正确的,哪些数据是错误的。对于一个数据集来说,假定其中有40%的错误数据,那么当我们随机划分数据的时候,如果70%的训练数据中有40%的错误数据和30%的数据,可以肯等的是,这个模型的得分一定不会太高,但你不能因此就认为你根据某个算法所构建的模型不适合这个数据,进而更改其他不适太完美的算法。所以这时我们就应该对模型进行交叉验证。
交叉验证(CrossValidation)又称循环估计是统计学上将数据样本切割成K小子集,利用不同的数据来训练多个同一模型,每一次训练时,选取大部分数据进行建模,保留小部分数据来进行评估。它比用train-test-split方法单次划分数据更加稳定、全面。K折交叉验证
K折交叉验证是交叉验证中常用的一种方法,其原理是现将数据划分成K段,每一段称之为这个数据的折,这样我们就得到了K个分段数据,接下来则进行K轮建模训练。第一轮训练以第2~K个数据为训练集,用第1个数据作为测试集,第二轮训练以第1和第3~K个数据为训练集,第2个数据为测试集,然后以此类推进行K轮训练,并记录下来每轮的得分情况,从而帮助我们对我们所构建的模型进行跟为全面的分析。这张图便是出交叉验证的原理K折交叉验证,其实现方法是sklearn.model_selection中的cross_val_score方法通常情况下我们基本上只用前三个参数和cv参数,estimate是你评估这个模型的算法也是你构建模型的算法,cv的作用是将数据化分成几段去进行交叉验证。下面我们以sklearn中的wine数据集为例,进行交叉验证fromsklearn.model_selectionimportcross_val_scorefromsklearn.datasetsimportload_winefromsklearn.linear_modelimportLogisticRegressionwine=load_wine()lgr=LogisticRegression()score=cross_val_score(lgr,wine.data,wine.target)print(score)print(score.mean())输出:[0.888888890.944444440.944444441.1.]0.9555555555555555
这里cross_val_score中的cv参数默认等于5,我们可以通过更改cv的值来选择我们将数据划分为多少折。分层K折交叉检验
上面一节我们学习了用K折交叉验证这种更为全面高效的方法去进行模型检验,那么请读者来思考这样一个问题:使用K折交叉检验还会不会出现类似train-test-split一样糟糕的情况?答案是会的,使用K折交叉检验依然会出现这种情况。就以wine数据集为例,让我们来看看wine的target[0000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222]
我们可以看到,wine的target是根据红酒的品质来排列的,品质为“0”的酒有48个,品质为“1”的酒有71个,剩下的59个是品质为“2”的酒。现在我们剔除品质为“1”的酒,在运行一遍K折交叉检验。scores=cross_val_score(lgr,x,y)输出:scores:[1.1.1.1.1.]score.mean=1.0
我们可以看到这样一个有趣的现象,接下来请读者自行思考一遍为什么会出现这样的原因。对,没错,正如你所想,剔除品质为“1”的酒后,样本总数只剩下107个且品质“0”:“2”≈“1”:“1”,假如我们忽略剩下的七个,进行五等分,那么每个五等分后每个小段对应的酒的品质都是相同的。
下面我们来模拟交叉训练的第一轮,以第一个折为测试集(全为品质为“0”的酒),以2~5个折为训练集(品质“0”:品质“2”≈“3”:“5”),所以用这种数据来进行训练和检测,实质上就等同于用训练集训练,再用训练集进行打分。所以会出现上述的结果。那么,该如何避免这种情况呢?
这时我们可以用分层K折交叉检验。分层K折交叉检验的原理和K折交叉检验的原理相同,只不过在取测试集和训练集的地方稍有不同。不再是选择一整个折作为测试集,剩下的折作为训练集,而是在每个折中选取前A%的数据作为测试集,每个折剩下的(1-A%)作为训练集,这样就能尽量的避免上述的情况出现。下面我们来看实现数据:剔除了品质为“1”的酒的wine.data和wine.target数据x=[]y=[]fori,valueinenumerate(wine.target):if(value!=1):x.append(wine.data[i])y.append(wine.target[i])x=np.array(x)y=np.array(y)scores=cross_val_score(lgr,x,y)print("scores:{}".format(scores))print("score.mean={}".format(scores.mean()))fromsklearn.model_selectionimportKFoldscores=cross_val_score(lgr,x,y,cv=KFold())print(scores)print(scores.mean())输出:[1.1.0.952380950.952380951.]0.980952380952381我们可以看到,尽管还是会出现scores=1的情况,但是出现的次数比之前少了两个,因为这是必然的,我们的样本数据太少(只有107个),但是如果数据足够多,出现这种情况的概率就会大大降低。这里我们导入了sklearn中的KFold分离器类,作用是将数据按层分离,可以通过n_split去控制分成几折。留一交叉验证和打乱划分和分组交叉验证
留一交叉验证(Leave-One-Out)也是交叉验证中比较常用的一个方法,其原理是将数据划分成K折,在单独的一个折将单个数据点作为测试集进行打分。对于小数据来说这种方法可能比前两种方法还要好,但是对于大数据来说,这种方法则非常耗时。下面我们还是以wine数据集来看其实现:fromsklearn.model_selectionimportLeaveOneOutloo=LeaveOneOut()scores=cross_val_score(lgr,wine.data,wine.target,cv=loo)print("scores_numbers:{}".format(len(scores)))print("score.mean={}".format(scores.mean()))输出:scores_numbers:178score.mean=0.9606741573033708
由于留一交叉验证是对单个数据点进行交叉验证的,所以这里我们就不展示单个数据点的打分情况(正确为1,错误为零),可以看到留一交叉验证对每个数据点都进行了打分,且大部分的数据都是正确的,说明LogisticRegression可以用在我们的模型上对数据进行预测。打乱划分交叉验证
打乱划分交叉验证也是交叉验证中的一种方法,其原理是对于一整个数据集,每次选取train_size%的数据作为训练集,test_size%的数据作为测试集进行训练并打分,训练集和测试集选取的地方并不交叉,共进行n次。
train_size和test_size可以是整数也可以是浮点数,整数表示选择多少个数据点作为训练集和数据集,但不应超过整个数据集的规模。浮点数表示选取数据集的K%作为训练集和测试集,同样训练集和测试集加和不应超过1。下面我们还是以wine数据集来看其实现train_size和test_size取整数:fromsklearn.model_selectionimportShuffleSplitshusffle_split=ShuffleSplit(n_splits=5,test_size=25,train_size=125,random_state=0)scores=cross_val_score(lgr,wine.data,wine.target,cv=shusffle_split)print("scores:{}".format(scores))print("score.mean={}".format(scores.mean()))输出:scores:[0.920.840.960.960.92]score.mean=0.9199999999999999train_size和test_size取浮点数:输出:scores:[0.933333330.888888890.933333330.977777780.93333333]score.mean=0.93333333333333336.2网格搜索
在上一节我们学习到了如何对一个模型的泛化能力进行全面的评估,但是请读者思考一个问题:一个模型的泛化能力弱是不是说明你所构建的模型的核心算法不对?
答案肯定是否定的,一个模型的泛化能力弱可能有多个影响因素,例如数据样本的大小、数据的准确性、算法的参数等问题。如果模型交叉验证的得分较低,先不要着急否定你的模型,尝试着去找出问题的所在。下面我们来学习如何通过改变模型的参数来提高模型的泛化能力。通过改变参数来提升模型的泛化能力,我们最常用的方法就是网格搜索。那么什么是网格搜索呢?我们以一个简单的网格搜索为例,假设一个模型中存在参数A
和参数B
,那么参数的取值就有100*100中可能。所以我们就可以把参数A和参数B以100*100的网格来列出来(如下图),不断的去进行尝试,最终求出最佳的参数使得模型的泛化能力最强。Python实现就是通过两个for循环不断的进行建模打分求出最优参数,而这就是一个简单的网格搜索。下面我们以sklearn中的iris数据集和具有RBF核的核SVM为例,介绍网格搜索的实现。fromsklearn.svmimportSVCfromsklearn.model_selectionimportcross_val_score,KFoldfromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitiris=load_iris()train_x,test_x,train_y,test_y=train_test_split(iris.data,iris.target,random_state=0)best_score=0best_C=0best_gamma=0Gamma=[x/100forxinrange(1,100)]C=GammaforgammainGamma:forcinC:svm=SVC(gamma=gamma,C=c)svm.fit(train_x,train_y)score=svm.score(test_x,test_y)ifscore>best_score:best_score=scorebest_C=cbest_gamma=gammaprint(best_score)print("best_C:{0}\nbest_gamma:{1}".format(best_C,best_gamma))输出:0.9736842105263158best_C:0.76best_gamma:0.02我们可以将数据可视化们可以发现,gamma的值越小、C的值越大,那么score的值就越大。所以,接下来我们可以缩小范围,增大参数精度,再次进行建模。Gamma=[x/10000forxinrange(100,300)]C=[x/1000forxinrange(700,800)]我们将gamma的范围缩小至[0.01,0.03],将C的范围缩小至[0.7,0.8],再次进行建模。0.9736842105263158best_C:0.799best_gamma:0.019此时,我们可以看到参数gamma的变化不大,只有0.001,而参数C则变化了0.0399,所以我们大致就可以认为C=0.76,gamma=0.02,就是这个模型的最佳参数。我们可以再次将数据可视化
可以看到,gamma和C的微小变动对score的影响不是很大。
两次用SVM构建的模型得平均分是97分,确实,不进行交叉验证之前这确实是一个非常好的模型。所以,接下来我们对模型进行交叉验证scores=cross_val_score(SVC(C=best_C,gamma=best_gamma),iris.data,iris.target,cv=KFold())print(scores)print(scores.mean())这里我们使用了分层K折交叉验证来对模型进行评估,我想读者一定可以猜到这个模型的得分并不是那么理想,让我们来看一下结果。[1.0.966666670.333333330.866666670.3]0.6933333333333334没错!平均得分只有0.69,这说明了我们利用网格搜索所得出的参数构建的模型存在过拟合现象。从交叉验证每一折的得分中我们可以看出,由我们找到的最佳参数构建的模型过度依赖于一部分数据(居然有0.96的得分),并且对大部分数据并不敏感,有两段数据的得分只有0.3。那么如何避免模型存在过拟合的现象呢?我们可以使用同时使用网格搜索和交叉检验,这样就可以避免模型存在过拟合的现象从而找出最佳参数fromsklearn.svmimportSVCfromsklearn.model_selectionimportcross_val_score,KFoldfromsklearn.datasetsimportload_irisiris=load_iris()best_score=0best_C=0best_gamma=0best_score_part=[]Gamma=[x/100forxinrange(1,100)]C=GammaforgammainGamma:forcinC:score=cross_val_score(SVC(C=c,gamma=gamma),iris.data,iris.target,cv=KFold())ifscore.mean()>best_score:best_score_part=scorebest_score=score.mean()best_C=cbest_gamma=gammaprint(best_score)print("best_C:{0}\nbest_gamma:{1}\nbest_score_part:{2}".format(best_C,best_gamma,best_score_part))输出:0.9333333333333333best_C:0.96best_gamma:0.17best_score_part:[1.1.0.866666670.966666670.83333333]我们再次将数据可视化
由于在(0.17,0.96,0.93)旁边的数据点较多,所以在这张图中我们看不太清楚最佳参数点的位置,但是据图分析,在交叉验证的辅助下,我们可以发现参数C越靠近0.96,score的值就越大,gamma越靠近0,score的值越大平均得分为0.93,虽然比0.97低了一点,但是我们可以对比两次模型选择的参数,可以看到两次选择的参数相差很大但是却降低模型过拟合的风险。所以我们再次调整参数的取值范围,参数gamma取值为[0.01,0.4],参数C的取值为[0.9,2.0],再次进行建模Gamma=[x/100forxinrange(1,40)]C=[x/100forxinrange(90,200)]此时我们可以看到:0.9333333333333333best_C:1.98best_gamma:0.08best_score_part:[1.1.0.866666670.966666670.83333333]我们再次将数据可视化这时我们可以看到,模型的平均得分并没有改变,改变的只有参数gamma和参数C的取值。随着C的增大,gamma有着缩小的趋势,所以我们再次扩大C的取值。C=[x/100forxinrange(300,1000)]结果:0.9400000000000001best_C:9.23best_gamma:0.05best_score_part:[1.1.0.866666670.966666670.86666667]但是当我们将C增大到一定程度的时候,乎没有什么变化,所以我们就可以选择C=9.23,gamma=0.05为最佳参数。
当然我们还可以使用另一种方法去选择最佳参数,sklearn库中为我们提供了GridSearchCV类,我们可以使用GridSearchCV来获取最佳参数。GridSearchCV可以为指定参数在给定的数值范围内自动选取最佳的参数,通常情况下我们指定参数都是构建一个带有我们想要选取最佳参数的参数名称和参数值的字典6.3评估指标在前面的两节中,我们讨论了如何用精度来评价一个解决分类问题的模型以及如何利用网格搜索找到最佳参数。但一个模型仅仅靠精度这一个指标是远远不够的,例如我们构建了一个可以诊断人类是否患有胃癌的模型并且精度达到了99.99%,那么如果你是前来检测的人,你是否相信模型诊断出的结果
不要忘了,我们构建的模型最终目的是用来解决问题的,如果只靠精度只一个评价指标就认定这个模型是一个可以在现实生活中可以被用来解决实际问题的模型是非常不理智的。所以在下面的章节中,我们来学习更多的可以用来评价模型的指标先让我们先了解一下对于不同问题所对应的评价指标
根据问题的不同,我们也将评估指标分为两大类,分类评估指标和回归评估指标。分类评估指标又分为Accuracy、Precision、Recall、F值、P-R曲线、POC曲线和AUC,回归评估指标又分为可释平方差得分、平均误差得分、均方误差、均方根差、交叉熵和R²值分类评估指标
对于一个分类问题,我们常见的主要分为二分类问题和多分类问题,接下来本节也是按照这两种类别分别进行讨论二分类评估指标二分类问题是机器学习中最常见也是最简单的问题,相信读者对二分类问题都不陌生了吧。通常,我们所说的二分类分为正类和反类。正类和反类没有什么特殊的规定,可以自己划定正类(positiveclass)和反类(negativeclass)。一般我们把我们心中想要的答案视为正类也叫真正例(truepositive,TP),与我们想要的答案背道而驰的视为反类也叫真反例(truenegative,TN),例如我们要检测一种食品是否合格,那么我们就可以将食品合格视为正类,不合格视为反类。但是也会有一些特殊的情况,如果一个合格的食品被错误的检验为合格,那么这种情况我们称之为假反例(falsenegative,FN)。如果一个不合格的食品被错误的检验成合格食品,那么这种情况我们称之为假正例(falsepositive,FP)
在现实生活中,我们希望我们构建的模型出现FN和FP的次数越小越好,而单纯的看模型的精度而不去考虑FN和FP,那么这样的模型即使精度高达100%也没有什么现实意义,不能用来解决问题
那么在进行评估之前,如何查看二分类的结果呢?这里我们介绍一种常用的方法——混淆矩阵(confusionmatrix)。通过利用sklearn.metrics中的confusion_matrix方法,我们可以查看通过模型预测的预测值和真实值之间的差异,也就是观察TP、TN、FP和TN的个数,且由于我们讨论的只有两个类别,所以confusion_matrix返回的是一个二维矩阵下面我们以sklearn中的breast-cancer(乳腺癌)数据集为例fromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLogisticRegressionfromsklearn.datasetsimportload_breast_cancerfromsklearn.metricsimportconfusion_matrixcancer=load_breast_cancer()train_x,test_x,train_y,test_y=train_test_split(cancer.data,cancer.target,random_state=0)log=LogisticRegression()log.fit(train_x,train_y)pred=log.predict(test_x)c_matrix=confusion_matrix(test_y,pred)print("confusion_matrix:\n{}".format(c_matrix))输出:confusion_matrix:[[512][684]]
上图是confusion_matrix返回的二维矩阵所表示的意义,通过观察混淆矩阵,我们便可以直观的观察到我们的模型是否能得到我们想要的结果。下面我们用混淆矩阵来比较决策树、支持核向量机和Logistic回归在cancer数据集上的效果log=LogisticRegression()log.fit(train_x,train_y)pred_log=log.predict(test_x)c_matrix_log=confusion_matrix(test_y,pred_log)print("confusion_matrix_log:\n{}".format(c_matrix_log))d_tree=DecisionTreeClassifier()d_tree.fit(train_x,train_y)pred_tree=d_tree.predict(test_x)c_matrix_tree=confusion_matrix(test_y,pred_tree)print("confusion_matrix_tree:\n{}".format(c_matrix_tree))svm=SVC()svm.fit(train_x,train_y)pred_svm=svm.predict(test_x)c_matrix_svm=confusion_matrix(test_y,pred_svm)print("confusion_matrix_svm:\n{}".format(c_matrix_svm))输出:confusion_matrix_log:[[512][684]]confusion_matrix_tree:[[503][1476]]confusion_matrix_svm:[[458][189]]
通过观察这三个混淆矩阵,我们通过FN和FP的数量来直观判断出logistic回归效果最好,决策树的效果最差。Logistic回归和支持核向量机在各方面表现得都要比决策树要好,但logistic回归预测出的TP和TN更少,所以从结果上来看,logistic回归构建的模型要比支持核向量机和决策树构建的模型预测效果更好精度(Accuracy)刚刚我们了解了用混淆矩阵来分析二分类的结果,其实有些读者可能也猜到了,上文这种分析混淆矩阵的结果就是我们前两节所讲的精度也叫精确率(Accuracy)。计算公式:即预测样本的正确数量除以样本总数=精度。计算精度的方法可以使用混淆矩阵也可以使用accuracy_score方法,但其实accuracy_score方法本质上还是利用混淆矩阵计算,只不过使用起来比混淆矩阵更为简单、方便准确率(Precision)下面我们来介绍另一种评估指标,准确度(precision)也叫阳性预测值(positivepredictionvalue,PPV)即预测正确的样本中有多少是真正例TP。准确率和精确率看上去很难区分,但准确率表示的是对正确样本中预测的准度,而精确率则表示的是整个样本中对预测正确样本的准度,预测正确的样本中既包含TP也包含TN。计算公式:召回率(Recall)召回率(Recall)也叫灵敏度(sensitivity)、命中率(hitrate)和真正例率(truepositiverate,TRR)指在所有正确的样本中有多少真正例TP。召回率适用于避免假反例FN的情况,例如网贷中区分信用良好的客户中的不良信用的用户、找到患病病人中的健康人等等。召回率越高,那么假反例FN被预测出来的概率就越高。计算公式:f-分数F-分数(f-score)也叫f-度量(f-measure),f-分数是准确率和召回率的平均调和函数,使用f-分数能够很好地展现出准确率和召回率之间的关系。计算公式:通常情况下我们一般取
,这一变体我们称之为也叫f1分数。f1分数作为二分类的评估指标普遍的比精度作为二分类的评估指标要好得多。计算公式:准确率-召回率曲线(P-R曲线)对于分类模型而言,我们通常可以调节做出分类决策的阈值来提高模型的准确率、召回率和f1-score等指标,但是我们在进行初次建模的时候,我们想要这个模型能够在某一个阈值上识别出80%的恶性肿瘤,可是不知道最佳的阈值,所以一般我们可以把所有可能取到的阈值先列出来,每一个阈值分别对应一个准确率和召回率,这样我们就可以将准确率和召回率绘制出一条曲线,以便于我们选择合适的阈值,这样的曲线就叫做准确率-召回率曲线(P-R曲线),能够满足我们需求的阈值我们也叫工作点根据这张图,我们可以看到越是靠近右上角,Precision和Recall的值就越高,而此时的阈值就是我们想要的阈值受试者工作特征曲线(POC曲线)受试者工作特征曲线(ReceiverOperatingCharacteristicsCurve,POC曲线),它显示的是真正率(TruePositiveRate,TPR)和假正率(FalsePositiveRate,FPR)之间的关系。ROC曲线和P-R曲线类似,都考虑的是所有可能取到的阈值。AUC
曲线下面积(AreaUndertheCurve),曲线指的是ROC曲线,AUC一般被用来计算ROC曲线的积分(即曲线于横坐标轴围成的面积),和平均准确率一样,AUC也是总结ROC曲线的一种方法。多分类评估指标多分类评估问题,说白了就是许多二分类问题组成的一个大的分类问题,我们前面讨论了许多关于二分类问题的评估指标,其实多分类问题对于这些指标也适用。例如可以表达分类结果的混淆矩阵confusion_
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度厂房租赁保证金退还协议4篇
- 2025年度智能设备价格信息保密及市场推广协议4篇
- 2025年度厂房租赁合同附带员工宿舍租赁条款4篇
- 二零二四唐山骨瓷品牌创新设计研发合作协议3篇
- 2025年度企业品牌策划合同范本(十)4篇
- 2024年04月江苏上海浦发银行南京分行在线视频笔试历年参考题库附带答案详解
- 2024美容美发店加盟合同
- 2025年茶叶出口基地承包经营合同范本4篇
- 专项工程承揽协议样本(2024年版)版B版
- 2024年03月浙江中国农业银行浙江省分行春季招考笔试历年参考题库附带答案详解
- 地理2024-2025学年人教版七年级上册地理知识点
- 2024 消化内科专业 药物临床试验GCP管理制度操作规程设计规范应急预案
- 2024-2030年中国电子邮箱行业市场运营模式及投资前景预测报告
- 基础设施零星维修 投标方案(技术方案)
- 人力资源 -人效评估指导手册
- 大疆80分钟在线测评题
- 2024届广东省广州市高三上学期调研测试英语试题及答案
- 中煤平朔集团有限公司招聘笔试题库2024
- 2023年成都市青白江区村(社区)“两委”后备人才考试真题
- 不付租金解除合同通知书
- 区域合作伙伴合作协议书范本
评论
0/150
提交评论