机器学习的目的是使学到的模型不仅对已知数据,而且对未知数据都能有很好的预测能力。当损失函数给定时,基于损失函数的模型训练误差(training error)和模型测试误差(test error)就是机器学习算法和模型的评估标准。训练误差主要用于判断给定问题是否容易训练学习;测试误差则用于反映机器学习算法对未知数据集的预测能力。通常,将学习算法对未知数据的预测能力称为泛化能力(generalization ability)。
如果一味地追求提高对训练数据的预测能力,所选模型的复杂度往往会比真实模型更高。这种现象称为过拟合(over-fitting)。过拟合是指学习时选择的模型所包含的参数过多,以致于出现这一模型对已知数据预测得很好,但对未知数据预测得很差的现象。可以说,模型选择旨在避免过拟合,并提高模型的预测能力。
1、模型选择
模型选择的方法有两种:一是从模型本身出发,利用结构风险最小化策略实现,即模型正则化(regularization);二是从从样本数据出发,通过随机切分样本数据集实现,即交叉验证方法(cross validation)。
1)正则化
模型选择的典型方法是正则化(regularization)。正则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项(regularizer)或惩罚项(penalty term)。正则化项一般是模型复杂度的单调递增函数,模型越复杂,正则化值就越大。比如,正则化项可以是模型参数向量的范数。
正则化一般具有如下形式:
其中,第1项是经验风险,第2项是正则化项,ramda大于等于0,为调整两者之间关系的系数。
正则化项可以取不同的形式,例如,回归问题中,损失函数是平方损失,正则化项可以是参数向量的L2范数:
这里,||w||表示参数向量w的L2范数。
第1项的经验风险较小的模型可能较复杂(有多个非零参数),这时第2项的模型复杂度会较大。正则化的作用是选择经验风险与模型复杂度同时较小的模型。
正则化符合奥卡姆剃刀(Occam's razor)原理。奥卡姆剃刀原理应用于模型选择时:在所有可能选择的模型中,能够很好地解释已知数据并且十分简单才是最好的模型。
从贝叶斯估计的角度来看,正则化项对应于模型的先验概率。可以假设复杂的模型有较小的先验概率,简单的模型有较大的先验概率。
2)交叉验证
另一种常用的模型选择方法是交叉验证。
如果给定的样本数据充足,进行模型选择的一种简单方法是随机地将数据集切分成三部分,分别为训练集(training set)、验证集(validation set)和测试集(test set)。训练集用来训练模型,验证集用于模型的选择,而测试集用于最终对学习方法的评估。在学习到的不同复杂度的模型中,选择对验证集有最小预测误差的模型。
交叉验证的基本想法是重复使用数据,把给定的数据进行切分,将切分的数据集组合为训练集与测试集,在此基础上反复进行训练、测试以及模型选择。
a.简单交叉验证
简单交叉验证方法是:首先随机地将已给数据分为两个部分,一部分作为训练集,另一部分作为测试集(例如,70%的数据为训练集,30%的数据为测试集);然后用训练集在各种条件下(例如,不同的参数个数)训练模型,从而得到不同的模型;在测试集上评价各个模型的测试误差,选出测试误差最小的模型。
b.S折交叉验证
应用最多的是S折交叉验证(S-fold cross validation),方法如下:首先随机地将已给数据切分为S个互不相交的大小相同的子集;然后利用S-1个子集的数据训练模型,利用余下的子集测试模型;将这一过程对可能的S种选择重复进行;最后选出S次评测中平均误差最小的模型。
c.留一交叉验证
S折交交叉验证的特殊情形是S=N,称为留一交叉验证(leave-one-out cross validation),往往在数据缺乏的情况下使用。这里,N是给定数据集的容量。
2、分类问题模型评估
针对分类问题,可采用准确率(accuracy)、精确率(precision)、召回率(Recall)、F1打分(F1 Score)、ROC曲线(ROC Curve)、混淆矩阵(Confusion Matrix)等指标进行模型评估。
1)准确率(accuracy)
准确率为被分对的样本数除以所有样本数。通常来说,准确率越高,分类器越好。计算公式如下:
TP:真正类,将正类预测为正类数;
FP:假正类,将正类预测为负类数;
FN:假负类,将负类预测为正类数;
TN:真负类,将负类预测为负类数。
2)精确率(precision)
精确率是针对预测结果而言的,表示预测为正的样本中有多少是真正的正样本。预测为正就有两种可能,一是把正类预测为正类(TP),另一种是把负类预测为正类(FP)。计算公式如下:
3)召回率(Recall)
召回率是针对原来样本而言的,表示样本中的正例有多少被预测正确了。也有两种可能,一种是把原来的正类预测成正类(TP),另一种是把原来的正类预测为负类(FN)。计算公式如下:
4)F1分数(F1 Score)
F1分数是分类问题的一个衡量指标,是精确率和召回率的调和平均数,最大为1,最小为0。计算公式如下:
5)ROC曲线(ROC Curve)
ROC(接收者操作特征,Receiver Operating Characteristic)曲线上每个点反映着对同一信号刺激的感受性。
横轴:假正类率(false positive rate, FDR)特异度,代表预测的正类中真实负类占所有负类的比例。
纵轴:真正类率(true positive rate, TPR)灵敏度,代表预测的正类中真实正类占所有正类的比例。
假设采用逻辑斯蒂回归分类器,其通过设定一个阈值如0.6,概率大于等于0.6的为正类,小于0.6的为负类。对应的就可以算出一组(FDR, TPR),在平面中得到对应坐标点。随着阈值的逐渐减小,越来越多的实例被预测为正类,但是这些正类中同样也掺杂着真正的负实例,即TPR和FDR会同时增大。阈值最大时,对应坐标点为(0,0);阈值最小时,对应坐标点(1,1)。如下图所示:
在ROC曲线中,理想目标是TPR=1,且FDR=0。即上图中(0,1)点,所以ROC曲线越靠拢(0,1)点,越偏离45°对角线越好。
另外一个重要的概念是,AUC(Area Under Curve),即ROC曲线下的面积,介于0和1之间。AUC作为数值可以直观的评价分类器的好坏,值越大越好。
6)混淆矩阵(Confusion Matrix)
混淆矩阵(Confusion Matrix)是一个误差矩阵,可用来评估监督机器学习算法的性能。混淆矩阵可以清晰的反映出真实值与预测值相互吻合的部分,也可以反映出与预测值不吻合的部分,如下图所示。
混淆矩阵也能够处理多类问题,如下图所示。
3、回归问题模型评估
针对回归问题,可采用均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)、确定系数(R-square)等指标进行模型评估。
1)均方误差(MSE)
均方误差计算公式如下:
2)均方根误差(RMSE)
均方根误差计算公式如下:
3)平均绝对误差(MAE)
平均绝对误差计算公式如下:
4)R方(R-square)决策系数
R方(R-square)或者调整后的R方(adjust R-square),通常用来描述数据对模型的拟合程度的好坏。R方计算公式如下:
式中,分母部分为样本数据y的固有方差(TSS),分子部分为回归模型的残差平方和(RSS)。需要注意的是,当自变量个数p增加时,会使残差平方和RSS减少,从而使R方变大。
调整后的R方计算公式如下:
式中,n为样本量个数,p为回归模型的自变量个数。
与R方不同的是,调整后的R方考虑了样本量个数和自变量个数的影响,这样一来,调整后的R方就不会由于回归中自变量个数增加而越来越接近1。
4、代码实例解析
1)交叉验证
a. 交叉验证的评价准则
croos_val_score
使用交叉验证最简单的方法是调用croos_val_score函数,下面例子演示怎样通过分割数据,拟合一个线性核支持向量机模型,计算5个连续次的分数,每次有不同的分割。
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)
分数的平均值和95%的置信区间是:
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
cross_ validate
允许指定多个评估指标;
除了测试分数之外,它还返回包含拟合时间、分数时间(以及可选的训练分数以及拟合估计值)的字典
cross_val_predict
交叉验证获得预测
cross_val_predict具有与cross_val_score的接口
适用于:
从不同模型获得的预测的可视化;
模型混合:当使用一个监督估计器的预测来训练集合方法中的另一个估计器时。
b. 交叉验证迭代器
KFold
>>>import numpy as np
>>> from sklearn.model_selection import KFold
>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2)
>>> for train, test in kf.split(X):
... print("%s %s" % (train, test))
LeaveOneOut
from sklearn.model_selection import LeaveOneOut
X= [1,2,3,4]
loo =LeaveOneOut()
for train, test in loo.split(X):
print("%s %s"% (train, test))
2)模型评估
a. 分类问题模型评估
准确率:accuracy_score
import numpy as np
from sklearn.metrics import accuracy_score
y_pred = [0, 2, 1, 3]
y_true = [0, 1, 2, 3]
print(accuracy_score(y_true, y_pred)) # 0.5
print(accuracy_score(y_true, y_pred, normalize=False)) # 2
精确率:precision_score
from sklearn.metrics import precision_score
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]
print(precision_score(y_true, y_pred, average='macro')) # 0.2222222222222222
print(precision_score(y_true, y_pred, average='micro')) # 0.3333333333333333
print(precision_score(y_true, y_pred, average='weighted')) # 0.2222222222222222
print(precision_score(y_true, y_pred, average=None)) # [0.66666667 0. 0. ]
召回率:recall_score
from sklearn.metrics import recall_score
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]
print(recall_score(y_true, y_pred, average='macro')) # 0.3333333333333333
print(recall_score(y_true, y_pred, average='micro')) # 0.3333333333333333
print(recall_score(y_true, y_pred, average='weighted')) # 0.3333333333333333
print(recall_score(y_true, y_pred, average=None)) # [1. 0. 0.]
F1分值:f1_score
from sklearn.metrics import f1_score
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]
print(f1_score(y_true, y_pred, average='macro')) # 0.26666666666666666
print(f1_score(y_true, y_pred, average='micro')) # 0.3333333333333333
print(f1_score(y_true, y_pred, average='weighted')) # 0.26666666666666666
print(f1_score(y_true, y_pred, average=None)) # [0.8 0. 0. ]
ROC曲线:roc_curve
>>> import numpy as np
>>> from sklearn.metrics import roc_curve, auc
>>> y = np.array([1, 1, 2, 2])
>>> scores = np.array([0.1, 0.4, 0.35, 0.8])
>>> fpr, tpr, thresholds = roc_curve(y, scores, pos_label=2)
>>> fpr
array([0. , 0. , 0.5, 0.5, 1. ])
>>> tpr
array([0. , 0.5, 0.5, 1. , 1. ])
>>> thresholds
array([1.8 , 0.8 , 0.4 , 0.35, 0.1 ])
>>> area = auc(fpr, tpr)
混淆矩阵:confusion_matrix
>>> from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0], [0, 0, 1], [1, 0, 2]])
混淆矩阵绘制见官方文档:https://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html#sphx-glr-auto-examples-model-selection-plot-confusion-matrix-py
b.回归问题模型评估
均方误差:mean_squared_error
>>> from sklearn.metrics import mean_squared_error
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> mean_squared_error(y_true, y_pred)
0.375
平均绝对误差:mean_absolute_error
>>> from sklearn.metrics import mean_absolute_error
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> mean_absolute_error(y_true, y_pred)
0.5
R方决策系数:r2_score
>>> from sklearn.metrics import r2_score
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> r2_score(y_true, y_pred)
0.948
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> r2_score(y_true, y_pred, multioutput='variance_weighted')
0.938