1 Sklearn 交叉验证
1.1原理图
将数据分为n份,一份作为测试数据,其他n-1份作为训练数据。
1.2 最基本交叉验证
#交叉验证法 from sklearn import svm from sklearn.model_selection import cross_val_score def Sklean_iris_cross_validation(): iris_dataset =datasets.load_iris() X,y =datasets.load_iris(return_X_y=True) print(X.shape,X.shape) X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.4,random_state=0) print("X_train,的形态:{}".format(X_train.shape)) print("X_test的形态:{}".format(X_test.shape)) print("y_train的形态:{}".format(y_train.shape)) print("y_test的形态:{}".format(y_test.shape)) svc =svm.SVC(kernel='linear',C=1).fit(X_train,y_train) print('交叉验证法前测试数据的得分:{:.2%}:\n'.format(svc.score(X_test,y_test))) svc =svm.SVC(kernel='linear',C=1) scores = cross_val_score(svc,X,y,cv=5)#实现交叉验证,cv=5:分5组 print('交叉验证法后测试数据的得分:{}:\n'.format(scores)) print('交叉验证法后测试数据的平均分:{:.2%}:\n'.format(scores.mean())) X_new = np.array([[4.5,3.6,1.3,0.3]]) svc.fit(X_train,y_train) prediction =svc.predict(X_new) print('预测的鸢尾花为:{}:\n'.format(iris_dataset['target_names'][prediction]))
输出
(150, 4) (150, 4) X_train,的形态:(90, 4) X_test的形态:(60, 4) y_train的形态:(90,) y_test的形态:(60,) 交叉验证法前测试数据的得分:96.67%:: 交叉验证法后测试数据的平均分:98.00%: 交叉验证法后测试数据的得分:[0.96666667 1. 0.96666667 0.96666667 1. ]: 预测的鸢尾花为:['setosa']:
1.3随机拆分
from sklearn.model_selection import ShuffleSplit #随机拆分,分为10份 shuffle_split =ShuffleSplit(test_size=.2,train_size=.7,n_splits=10) scores = cross_val_score(svc,X,y,cv=shuffle_split) print('随机差分交叉验证法后测试数据的得分:{}:\n'.format(scores)) print('随机差分交叉验证法后测试数据的平均得分:{:.2%}:\n'.format(scores.mean())) svc.fit(X_train,y_train) prediction =svc.predict(X_new) print('随机拆分预测的鸢尾花为:{}:\n'.format(iris_dataset['target_names'][prediction]))
输出
随机拆分交叉验证法后测试数据的得分:[0.966666671. 0.96666667 0.933333330.93333333 0.96666667 1. 0.96666667 1. 0.96666667]: 随机拆分交叉验证法后测试数据的平均得分:97.00%: 随机拆分预测的鸢尾花为:['setosa']:
1.4 挨个试试
#挨个试试 cv = LeaveOneOut() scores =cross_val_score(svc,X,y,cv=cv) print("迭代次数:{}".format(len(scores))) print("挨个试试交叉验证法后测试数据的平均得分:{:.2%}".format(scores.mean())) svc.fit(X_train,y_train) prediction =svc.predict(X_new) print('挨个试试预测的鸢尾花为:{}:\n'.format(iris_dataset['target_names'][prediction]))
输出
迭代次数:150 挨个试试交叉验证法后测试数据的平均得分:98.00% 挨个试试预测的鸢尾花为:['setosa']:
注意:交叉测试性能好,但是耗时长
测试方法 |
得分 |
不用拆分 |
96.67% |
普通拆分 |
98.00% |
随机拆分 |
97.00% |
挨个试试 |
98.00% |
2网格搜索
from sklearn.linear_model import Lasso def Grid_search(): warnings.filterwarnings("ignore") data =datasets.load_wine() X_train,X_test,y_train,y_test = train_test_split(data.data,data.target,random_state=38) best_score = 0 for alpha in[0.01,0.1,1.0,10.0]: for max_iter in[10,1000,5000,10000]: lasso =Lasso(alpha=alpha,max_iter=max_iter) lasso.fit(X_train,y_train) score =lasso.score(X_test,y_test) if score > best_score: best_score = score best_params={"alpha":alpha,"最大迭代数":max_iter} print("random_state=38,模型最高得分:\n{:.2%}".format(best_score)) print("random_state=38,最高得分时的参数:\n{}".format(best_params))
输出
random_state=38,模型最高得分: 88.85% random_state=38,最高得分时的参数: {'alpha':0.01, '最大迭代数': 1000}
由于random_state=38,数据不变化,我们把random_state改为0
X_train,X_test,y_train,y_test =train_test_split(data.data,data.target, random_state=0) best_score = 0 for alpha in[0.01,0.1,1.0,10.0]: for max_iterin [10,1000,5000,10000]: lasso= Lasso(alpha=alpha,max_iter=max_iter) lasso.fit(X_train,y_train) score= lasso.score(X_test,y_test) ifscore > best_score: best_score = score best_params={"alpha":alpha,"最大迭代数":max_iter} print("random_state=0,模型最高得分:\n{:.2%}".format(best_score)) print("random_state=0,最高得分时的参数:\n{}".format(best_params))
输出
random_state=0,模型最高得分: 82.99% random_state=0,最高得分时的参数: {'alpha':0.1, '最大迭代数': 1000}
由于random_state=0,得分下降。接下来我们把网络搜索与拆分结合在一起。
best_score = 0 for alpha in[0.01,0.1,1.0,10.0]: for max_iter in[10,1000,5000,10000]: lasso =Lasso(alpha=alpha,max_iter=max_iter) scores =cross_val_score(lasso,X_train,y_train,cv=6) score =np.mean(scores) if score >best_score: best_score =score best_params={"alpha":alpha,"最大迭代数":max_iter} print("交叉验证与网格搜索模型最高得分:\n{:.2%}".format(best_score)) print("交叉验证与网格搜索最高得分时的参数:\n{}".format(best_params))
输出
交叉验证与网格搜索模型最高得分: 86.52% 交叉验证与网格搜索最高得分时的参数: {'alpha':0.01, '最大迭代数': 1000}
上面的86.52%为交叉测试得分,不采用交叉测试,最终最高得分可以通过以下方法获得。
i = 0 for key,value inbest_params.items(): if i==0: alpha = float(value) if i==1: max_iter =float(value) i = i+1 print("alpha:",alpha) print("max_iter:",max_iter) lasso =Lasso(alpha=alpha,max_iter=max_iter).fit(X_train,y_train) print("最终测试数据得分{:.2%}".format(lasso.score(X_test,y_test)))
输出
alpha: 0.01 max_iter: 1000.0 最终测试数据得分81.93%
这些过程我们可以让GridSeearchCV来帮我们简化
from sklearn.model_selection import GridSearchCV #用GridSeearchCV简化 params = {"alpha":[0.01,0.1,1.0,10.0],"max_iter":[10,1000,5000,10000]} gread_search = GridSearchCV(lasso,params,cv=6) gread_search.fit(X_train,y_train) print("模型最高得分:\n{:.2%}".format(gread_search.score(X_test,y_test))) print("最高得分时的参数:\n{}".format(gread_search.best_params_)) print("交叉验证最高得分:\n{:.2%}".format(gread_search.best_score_))
输出
模型最高得分: 81.93% 最高得分时的参数: {'alpha': 0.01, 'max_iter': 1000} 交叉验证最高得分: 86.52%
总结
Lasso回归,红酒数据
参数 |
alpha |
max_iter |
得分 |
random_state=38 |
0.01 |
1000 |
88.85% |
random_state=0 |
0.1 |
1000 |
82.99% |
交叉验证+网格搜索模型 |
0.1 |
1000 |
86.52% |
网格搜索模型 |
0.1 |
1000 |
81.93% |
GridSeearchCV简化 |
0.1 |
1000 |
86.52% |
不用交叉 |
0.1 |
1000 |
81.93% |
3可信度评估
3.1 predict_proba
from sklearn.datasets import make_blobs from sklearn.naive_bayes import GaussianNB from sklearn.svm import SVC def accuracy_rate(): #cluster_std:方差 X,y =make_blobs(n_samples=200,centers=2, random_state=1,cluster_std=5) plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.cool,edgecolor='k') plt.show() X_train, X_test,y_train, y_test = train_test_split(X, y, random_state=68) gnb =GaussianNB() gnb.fit(X_train,y_train) predict_proba =gnb.predict_proba(X_test) print("预测准确率形态{}".format(predict_proba.shape)) print("预测准确率前5个数据:\n",predict_proba[:5]) x_min,x_max = X[:,0].min()-0.5,X[:,0].max()+0.5 y_min,y_max = X[:,1].min()-0.5,X[:,1].max()+0.5 xx, yy =np.meshgrid(np.arange(x_min, x_max, .02),np.arange(y_min, y_max, .02)) Z =gnb.predict_proba(np.c_[xx.ravel(),yy.ravel()])[:,1] Z = Z.reshape(xx.shape) #画等高线 plt.contourf(xx,yy,Z,cmap=plt.cm.summer,alpha=0.8) #画散点图 plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolors='k') plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,edgecolors='k') plt.xlim(xx.min(),xx.max()) plt.ylim(yy.min(),yy.max()) plt.xticks(()) plt.yticks(()) plt.show()
输出
预测准确率形态(50, 2) 预测准确率前5个数据: [[0.98849996 0.01150004] [0.0495985 0.9504015 ] [0.01648034 0.98351966] [0.8168274 0.1831726 ] [0.00282471 0.99717529]]
测试集50个数据。形态【属于0的概率,属于1的概率】
- 第1条数据属于0的概率99%,属于1的概率1% ->属于0
- 第2条数据属于0的概率5%,属于1的概率95% ->属于1
- 第3条数据属于0的概率2%,属于1的概率98% ->属于1
- 第4条数据属于0的概率82%,属于1的概率18% ->属于0
- 第4条数据属于0的概率0%,属于1的概率100% ->属于1
3.2 decision_function
有些模型没有predict_proba,但是有decision_function函数。
svc =SVC().fit(X_train,y_train) dec_func = svc.decision_function(X_test) print("决定系数形态{}".format(dec_func.shape)) print("决定系数前5个数据:\n",dec_func[:5]) Z =svc.decision_function(np.c_[xx.ravel(),yy.ravel()]) Z = Z.reshape(xx.shape) #画等高线 plt.contourf(xx,yy,Z,cmap=plt.cm.summer,alpha=0.8) #画散点图 plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolors='k') plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,edgecolors='k') plt.xlim(xx.min(),xx.max()) plt.ylim(yy.min(),yy.max()) plt.xticks(()) plt.yticks(()) plt.show()
输出
决定系数形态(50,) 决定系数前5个数据: [-1.36071347 1.53694862 1.78825594-0.96133081 1.81826853]
负的分类0,正的分类1
- 1 -1.36071347 <0 属于0
- 2 1.53694862 >0 属于1
- 3 1.78825594 >0 属于1
- 4 -0.96133081 <0 属于0
- 5 1.81826853 >0 属于1
结果与上面是一致的
4 其他指标
4.1几个基本概念
大家都知道,人工智能通过训练样本来对系统通过深度学习的算法来进行训练,然后通过测试样本来对训练样本进行测试。“基于样本分析算法的优劣”中的样本仅对于测试样本而言。在这里样本的取样结果质量有几个关键的指标:正确率、精确度、召回率和F1分数。在介绍这些指标之前,我们先来看一下下面四个概念:
l T(True):真样本;
l F(False):假样本;
l P(Positive):判断为真;
l N(Negative):判断为假。
由此,我们又可以推断出如下四个概念:
l TP True Positive:正确的判断为真(有病判断为有病,又称真阳性)
l FN False Negative:错误的判断为假(有病判断为没病,又称假阴性,属于漏诊)
l FP False Positive:错误的判断为真(没病判断为有病,又称假阳性,属于误诊)
l TN True Negative:正确的判断为假(没病判断为没病,又称真阴性)
由此得到下面一个表:
实际 |
|||
真(T) |
假(F) |
||
判断 |
真(P) |
TP |
FP |
假(N) |
FN |
TN |
4.2精确度、召回率、准确性、Fn Score
这个表,成为混淆矩阵。下面把这张表再进行加工。
通过这张表,我们得到了所有的指标,在这些指标中,以下2个是特别有用的:
- 精确度(PPV)=TP/(TP+FP):真阳性在判断为真的比例数。是衡量所有判断为真的样例的质量;
- 召回率(TPR)= TP/(TP+FN):在所有的真样本中有多少被找出。
另外还有2项是此重要的,其中1项没有在上表中体现:
- 特异度(Specificity)= TN/(FP+FN):即真阴率,实际的假样本被正确地找出;
- 准确性=(TP + TN) / (TP + FP + TN + FN):所有的查出的真阳与真阴数所占所有样本的比率。
为了让大家更不好的理解这些指标,我们来看一个案例。某电子商务网站,根据Linda的历史购物框推选了15个商品,其中12个是推荐正确的,3个是推荐错误的,这个系统中有50个商品,其中符合推荐给Linda的应该为20个,其他30个为不符合的。下面让我们来看一下上面谈到的各个指标:
- 精确度(Precision)=12/15=80%;
- 召回率(Recall)=12/20=60%;
- 特异度(Specificity)=(30-(15-12))/30=27/30=90%;
- 准确性=(12+ Specificity)/50=(12+27)/50=78%。
那么是不是精确度或者召回率越高越好呢,那可不一定,要视具体的产品而定。比如新冠病毒的检测软件,我们宁可降低精确度,也要保证召回率,不放过一个病例。这种情况即所谓的“宁错杀一百,不放过一个”的策略。比如:样本中有50真样本,50假样本,判断得到95个,其中50个为真,45个为假。这样精度50/95=53%,召回率=50/50=100%,由此可见这种算法精确度并不高,只有53%,而召回率达到了100%。另外一种情况,是可以牺牲召回率,而保证精确度,比如精准扶贫,对于每一个扶贫农夫开销是很大的,所以不允许存在把钱花在假贫困户上。比如:同样样本中有50真样本,判断得到15个,其中15个为真,其中0个为假。这样精度15/15=100%,召回率=15/50=30%,由此可见这种算法精确度很高高,达到100%,而召回率不高,仅为30%。
一般而言精确度和召回率应该是负相关的,如果两个值都低说明算法有了问题了,这里提出了F0.5分数、F1分数、F2分数、F3分数等指标。用的最多的是F1分数。
Fn分数(F1Score)=(1+n2)×精度×召回率×2 / (n2×精确度+召回率)
所以:
- F0.5分数(F0.5Score)=1.25×精度×召回率/ (0.25×精度+召回率);
- F1分数(F1 Score)=2×精度×召回率/ (1×精度+召回率);
- F2分数(F1 Score)=5×精度×召回率/ (4×精度+召回率)。
这样在上面的商品推荐案例中:
- F0.5 Score=1.25×80%×60%/(0.25×80%+60%)=0.6/0.8=75%;
F1 Score=2×80%×60%/(1×80%+60%)=0.96/1.4=68%;
- F2 Score=5×80%×60%/(4×80%+60%)=2.4/3.8=63%。
一般而言,如果Fn分数低于60%算法就有问题了,如果低于50%,就存在严重事故了。由此可见n值越大,要求越严格。
接下来介绍几个更高级的度量图