模型评估与改进
交叉验证
交叉验证是一种评估泛化性能的统计学方法,它比单次划分训练集和测试集的方法更加稳定、全面。在交叉验证中,数据被多次划分,并且需要训练多个模型。
最常用的交叉验证是k折交叉验证,其中k是由用户指定的数字,通常取5或者10。
在执行5折交叉验证时,首先将数据划分为(大致)相等的5部分,每一部分叫做折。
接下来训练一系列模型,使用第一折作为测试集、其他折(2~5)作为训练集来训练第一个模型。
利用2~5折中的数据来构建模型,然后在1折上评估精度。
之后构建另一个模型,这次使用2折 作为测试集,1、3、4、5折中的数据作为训练集。
利用3、4、5折作为测试集重复这一过程。
对于将数据划分为训练集和测试集的这五次划分 ,每一次都需要计算精度。
最后我们得到了5个精度值。
mglearn.plots.plot_cross_validation()
通常来说,数据的前五分之一是第1折,第二个五分之一是第2折,其此类推。
scikit-learn中的交叉验证
scikit-learn是利用model_selection模块中的cross_val_score函数来实现交叉验证的。
cross_val_score函数的参数是我们想要评估的模型、训练数据与真实标签。
我们在iris数据集上对LogisticRegression进行评估:
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
iris=load_iris()
logreg=LogisticRegression()
scores=cross_val_score(logreg,iris.data,iris.target,cv=5)
print("Cross-validation scores:{}".format(scores))
Cross-validation scores:[0.96666667 1. 0.93333333 0.96666667 1. ]
总结交叉验证精度的一种常用方法是计算平均值:
print("Average cross-validation score:{:.2f}".format(scores.mean()))
Average cross-validation score:0.97
分层k折交叉验证和其他策略
首先,我们康康iris数据集:
from sklearn.datasets import load_iris
iris=load_iris()
print("Iris labels:\n{}".format(iris.target))
输出:
Iris labels:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
数据前三分之一是类别0,中间三分之一是类别1,最后三分之一是类别2。
简单k折策略在这里失效了,故我们使用分层k折交叉验证。
在分层交叉验证中,我们划分数据,使每个折中类别之间的比例与整个数据集中的比例相同。
mglearn.plots.plot_stratified_cross_validation()
留一交叉验证
另一种常用的交叉验证方法是留一法。
可以将留一法交叉验证看作是每折只包含单个样本的k折交叉验证。
对于每次划分,选择单个数据点作为测试集。
from sklearn.model_selection import LeaveOneOut
loo=LeaveOneOut()
logreg = LogisticRegression()
scores=cross_val_score(logreg,iris.data,iris.target,cv=loo)
print("Number of cv iterations:",len(scores))
print("Mean accuracy:{:.2f}".format(scores.mean()))
Number of cv iterations: 150
Mean accuracy:0.97
打乱划分交叉验证
在打乱划分交叉验证中,每次划分为训练集取样train_size个点,为测试集取样test_size个(不相交的)点。
将这一划分方法重复n_iter次。
mglearn.plots.plot_shuffle_split()
下面的代码将数据集划分为50%的训练集和50%的测试集,共运行10次迭代:
from sklearn.model_selection import ShuffleSplit
shuffle_split =ShuffleSplit(test_size=.5,train_size=.5,n_splits=10)
scores=cross_val_score(logreg,iris.data,iris.target,cv=shuffle_split)
print("Cross-validation scores:\n{}".format(scores))
Cross-validation scores:
[0.97333333 0.96 0.98666667 0.98666667 0.97333333 0.98666667
0.92 0.97333333 0.97333333 0.93333333]
分组交叉验证
另一种交叉验证适用于数据中的分组高度相关时。
下面这个示例用到了一个由groups数组指定分组的模拟数据集。
这个数据集包含12个数据点,且对于每个数据点,groups指定了该点所属的分组。
一共分成四组,前3个样本属于第一组,接下来4个样本属于第二组,以此类推:
from sklearn.model_selection import GroupKFold
from sklearn.datasets import make_blobs
#创建模拟数据集
X,y=make_blobs(n_samples=12,random_state=0)
#假设前三个样本属于同一组,接下来4个样本属于同一组,以此类推
groups=[0,0,0,1,1,1,1,2,2,3,3,3]
scores=cross_val_score(logreg,X,y,groups,cv=GroupKFold(n_splits=3))
print("Cross-validation scores:\n{}".format(scores))
mglearn.plots.plot_group_kfold()
网格搜索
简单网格搜索
参数过拟合的风险与验证集
mglearn.plots.plot_threefold_split()
带交叉验证的网格搜索
mglearn.plots.plot_cross_val_selection()
mglearn.plots.plot_grid_search_overview()
评估指标与评分
二分类指标
对于二分类问题,我们通常会说正类和反类。
错误的阳性预测叫做假正例,错误的阴性预测叫做假反例。
在统计学中,假正例也叫做第一类错误,假反例也叫作第二类错误。
mglearn.plots.plot_confusion_matrix_illustration()
"9与其他"分类任务的混淆矩阵
mglearn.plots.plot_binary_confusion_matrix()
二分类混淆矩阵
mglearn.plots.plot_decision_threshold()
受试者工作特征(ROC)和AUC
有一种常用的工具可以分析不同阈值的分类器行为:受试者工作特征曲线,简称为ROC曲线。与准确率-召回率曲线类似,ROC曲线考虑了给定分类器的所有可能的阈值,但它显示的是假正例率和真正例率 ,而不是报告准确率和召回率。
真正例率只是召回率的另一个名称,而假正例率则是假正例占所有反类样本的比例
from sklearn.metrics import roc_curve
from sklearn import svm
from sklearn.svm import SVC
fpr,tpr,thresholds=roc_curve(y_test,svc.decision_function(X_test))
X,y=make_blobs(n_samples=(4000,500),centers=2,cluster_std=[7.0,2],random_state=22)
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0)
svc=SVC(gamma=.05).fit(X_train,y_train)
precision,recall,thresholds=precision_recall_curve(y_test,svc.decision_function(X_test))
plt.plot(fpr,tpr,label="ROC Curve")
plt.xlabel("FPR")
plt.ylabel("TPR(recall)")
#找到最接近于0的阈值
close_zero=np.argmin(np.abs(thresholds))
plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label="threshold zero",fillstyle="none",c='k',mew=2)
plt.legend(loc=4)
未完待续
多分类指标
一般来说,多分类结果比二分类结果更加难以理解。
除了精度,常用的工具有混淆矩阵和分类报告,下面我们将这两种详细的评估方法应用于对digits数据集中10种不同的手写数字进行分类的任务:
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn import datasets
digits = datasets.load_digits()
X_train,X_test,y_train,y_test=train_test_split(digits.data,digits.target,random_state=0)
lr=LogisticRegression().fit(X_train,y_train)
pred=lr.predict(X_test)
print("Accuracy:{:.3f}".format(accuracy_score(y_test,pred)))
print("Confusion matrix:\n{}".format(confusion_matrix(y_test,pred)))
Accuracy:0.951
Confusion matrix:
[[37 0 0 0 0 0 0 0 0 0]
[ 0 40 0 0 0 0 0 0 2 1]
[ 0 1 40 3 0 0 0 0 0 0]
[ 0 0 0 43 0 0 0 0 1 1]
[ 0 0 0 0 37 0 0 1 0 0]
[ 0 0 0 0 0 46 0 0 0 2]
[ 0 1 0 0 0 0 51 0 0 0]
[ 0 0 0 1 1 0 0 46 0 0]
[ 0 3 1 0 0 0 0 0 43 1]
[ 0 0 0 0 0 1 0 0 1 45]]
scores_image=mglearn.tools.heatmap(confusion_matrix(y_test,pred),xlabel='predicted label',ylabel='true label',xticklabels=digits.target_names,yticklabels=digits.target_names,cmap=plt.cm.gray_r,fmt="%d")
plt.title("confusion matrix")
plt.gca().invert_yaxis()
10个数字分类任务的混淆矩阵
利用classification_report函数,我们可以计算每个类别的准确率、召回率和 f f f-分数:
from sklearn.metrics import classification_report
print(classification_report(y_test,pred))
precision recall f1-score support
0 1.00 1.00 1.00 37
1 0.89 0.93 0.91 43
2 0.98 0.91 0.94 44
3 0.91 0.96 0.93 45
4 0.97 0.97 0.97 38
5 0.98 0.96 0.97 48
6 1.00 0.98 0.99 52
7 0.98 0.96 0.97 48
8 0.91 0.90 0.91 48
9 0.90 0.96 0.93 47
accuracy 0.95 450
macro avg 0.95 0.95 0.95 450
weighted avg 0.95 0.95 0.95 450