机器学习算法:模型选择与模型评估

机器学习的目的是使学到的模型不仅对已知数据,而且对未知数据都能有很好的预测能力。当损失函数给定时,基于损失函数的模型训练误差(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。计算公式如下:

F1分数计算公式

5)ROC曲线(ROC Curve)

ROC(接收者操作特征,Receiver Operating Characteristic)曲线上每个点反映着对同一信号刺激的感受性。

横轴:假正类率(false positive rate, FDR)特异度,代表预测的正类中真实负类占所有负类的比例。

FDR计算公式

纵轴:真正类率(true positive rate, TPR)灵敏度,代表预测的正类中真实正类占所有正类的比例。

TPR计算公式

假设采用逻辑斯蒂回归分类器,其通过设定一个阈值如0.6,概率大于等于0.6的为正类,小于0.6的为负类。对应的就可以算出一组(FDR, TPR),在平面中得到对应坐标点。随着阈值的逐渐减小,越来越多的实例被预测为正类,但是这些正类中同样也掺杂着真正的负实例,即TPR和FDR会同时增大。阈值最大时,对应坐标点为(0,0);阈值最小时,对应坐标点(1,1)。如下图所示:


ROC曲线示例

在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方计算公式如下:

R方计算公式

式中,分母部分为样本数据y的固有方差(TSS),分子部分为回归模型的残差平方和(RSS)。需要注意的是,当自变量个数p增加时,会使残差平方和RSS减少,从而使R方变大。

调整后的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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容