You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8.6 KiB

12.5 验证算法性能

上一节,我们已经学会了怎样使用 sklearn 提供的接口来构建一棵决策树模型。那这节就要来看看我们构建的模型的准确度高不高了。然而验证该模型的性能存在两个问题。一是什么样的指标能够衡量该模型的性能,二是怎样才能不偏不倚地验证算法的性能。接下来,我会一一解答。

首先是准确度的量化问题。本章一开始就提到过,该数据集不能用准确率这个指标来衡量我们的算法的性能。因为该数据集的标签是不平衡的。那什么样的指标能够衡量这种不平衡的数据呢?那就是 F1 Score !

想要弄明白 F1 Score 所代表的意义,就需要先从混淆矩阵说起。以癌症检测系统为例,癌症检测系统的输出不是有癌症就是健康,这里为了方便,就用 1 表示患有癌症0 表示健康。假设现在拿 10000 条数据来进行测试,其中有 9978 条数据的真实类别是 0 ,系统预测的类别也是 0 ,有 2 条数据的真实类别是 1 却预测成了 0 ,有 12 条数据的真实类别是 0 但预测成了 1 ,有 8 条数据的真实类别是 1 ,预测结果也是 1 。

如果我们把这些结果组成如下矩阵,则该矩阵就成为混淆矩阵

真实预测 0 1
0 9978 12
1 2 8

混淆矩阵中每个格子所代表的的意义也很明显,意义如下:

真实预测 0 1
0 预测0正确的数量 预测1错误的数量
1 预测0错误的数量 预测1正确的数量

如果将正确看成是 True ,错误看成是 False 0 看成是 Negtive 1 看成是 Positive 。然后将上表中的文字替换掉,混淆矩阵如下:

真实预测 0 1
0 TN FP
1 FN TP

因此 TN 表示真实类别是 Negtive ,预测结果也是 Negtive 的数量; FP 表示真实类别是 Negtive ,预测结果是 Positive 的数量FN 表示真实类别是 Positive ,预测结果是 Negtive 的数量; TP 表示真实类别是 Positive ,预测结果也是 Positive 的数量。

很明显,当 FN 和 FP 都等于 0 时,模型的性能应该是最好的,因为模型并没有在预测的时候犯错误。即如下混淆矩阵:

真实预测 0 1
0 9978 0
1 0 22

所以模型分类性能越好,混淆矩阵中非对角线上的数值越小。

然后还需要明白两个概念:精准率和召回率。

精准率( Precision ) 指的是模型预测为 Positive 时的预测准确度,其计算公式如下:


Precisioin=\frac{TP}{TP+FP}

假如癌症检测系统的混淆矩阵如下:

真实预测 0 1
0 9978 12
1 2 8

则该系统的精准率=8/(8+12)=0.4。

0.4 这个值表示癌症检测系统的预测结果中如果有 100 个人被预测成患有癌症,那么其中有 40 人是真的患有癌症。也就是说,精准率越高,那么癌症检测系统预测某人患有癌症的可信度就越高。

召回率(Recall) 指的是我们关注的事件发生了,并且模型预测正确了的比值,其计算公式如下:


Precisioin=\frac{TP}{FN+TP}

假如癌症检测系统的混淆矩阵如下:

真实预测 0 1
0 9978 12
1 2 8

则该系统的召回率=8/(8+2)=0.8。

从计算出的召回率可以看出,假设有 100 个患有癌症的病人使用这个系统进行癌症检测,系统能够检测出 80 人是患有癌症的。也就是说,召回率越高,那么我们感兴趣的对象成为漏网之鱼的可能性越低。

那么精准率和召回率之间存在着什么样的关系呢?举个例子,假设有这么一组数据,菱形代表 Positive ,圆形代表 Negtive 。

现在需要训练一个模型对数据进行分类,假如该模型非常简单,就是在数据上画一条线作为分类边界。模型认为边界的左边是 Negtive右边是Positive 。如果该模型的分类边界向左或者向右移动的话,模型所对应的精准率和召回率如下图所示:

从上图可知,模型的精准率变高,召回率会变低,精准率变低,召回率会变高。

那么有没有像准确率一样值越高说明性能越好而且能够兼顾精准率和召回率的指标呢那就是F1 Score

F1 Score 是统计学中用来衡量二分类模型精确度的一种指标。它同时兼顾了分类模型的准确率和召回率。F1 Score 可以看作是模型准确率和召回率的一种加权平均,它的最大值是 1 ,最小值是 0 。其公式如下:


F1=\frac{2*precision*recall}{precision+recall}
  • 假设模型 A 的精准率为 0.2 ,召回率为 0.7 ,那么模型 A 的 F1 Score 为 0.31111 。

  • 假设模型 B 的精准率为 0.7 ,召回率为 0.2 ,那么模型 B 的 F1 Score 为 0.31111 。

  • 假设模型 C 的精准率为 0.8 ,召回率为 0.7 ,那么模型 C 的 F1 Score 为 0.74667 。

  • 假设模型 D 的精准率为 0.2 ,召回率为 0.3 ,那么模型 D 的 F1 Score 为 0.24。

从上述 4 个模型的各种性能可以看出模型C的精准率和召回率都比较高因此它的 F1 Score 也比较高。而其他模型的精准率和召回率要么都比较低,要么一个低一个高,所以它们的 F1 Score 比较低。

这也说明了只有当模型的精准率和召回率都比较高时 F1 Score 才会比较高。这也是 F1 Score 能够同时兼顾精准率和召回率的原因。

嗯,现在知道用什么指标来衡量模型性能了,那怎样才能不偏不倚地判别模型性能的好坏呢?那就是交叉验证!

一般在真实业务中,我们可能没有真正意义上的测试集,或者说不知道测试集中的数据长什么样子。那么怎样在没有测试集的情况下来验证模型好还是不好呢?这个时候就需要验证集了。

那么验证集从何而来,很明显,可以从训练集中抽取一小部分的数据作为验证集,用来验证模型的性能。

但如果仅仅是从训练集中抽取一小部分作为验证集的话,有可能会让对模型的性能有一种偏见或者误解。

比如现在要对手写数字进行识别,那么我就可能会训练一个分类模型。但可能模型对于数字1的识别准确率比较低 ,而验证集中没多少个数字为1的样本,然后用验证集测试完后得到的准确率为 0.96 。然后您可能觉得哎呀,我的模型很厉害了,但其实并不然,因为这样的验证集让您的模型的性能有了误解。那有没有更加公正的验证算法性能的方法呢?有,那就是k-折交叉验证

K-折交叉验证把原始训练数据集分割成K个不重合的⼦数据集然后做K次模型训练和验证。每⼀次使⽤⼀个⼦数据集验证模型并使⽤其它K1个⼦数据集来训练模型。在这K次训练和验证中每次⽤来验证模型的⼦数据集都不同。最后对这K次在验证集上的性能求平均。

OK明白了什么是 F1 Score 和交叉验证之后。我们就可以使用 sklearn 提供好了的接口来验证我们模型的性能了,代码十分简单。

# 导入K折功能
from sklearn.model_selection import KFold
from sklearn.metrics import f1_score

# 提取数据集中的标签
y = transactions['Class']
# 将Class这一列删除也就相当于提取了数据集中的所有特征
X = transactions.drop(['Class'])

# 5折交叉验证
kf = KFold(n_splits=5)
# 平均f1 score
mean_f1_score = 0

# 开始5折交叉验证
for train_index, test_index in kf.split(X):
    #train_X表示训练集中的数据train_y表示训练集中的标签
    train_X, train_y = X[train_index], y[train_index]
    #test_X表示验证集中的数据test_y表示验证集中的标签
    test_X, test_y = X[test_index], y[test_index]
    smote_pipeline.fit(train_X, train_y)
    pred = smote_pipeline.predict(test_X)

    score = f1_score(test_y, pred)
    mean_f1_score += score

# 因为是5折所以除以5
mean_f1_score /= 5
print(mean_f1_score)

可以看到,我们的决策树模型的 F1 Score 为 0.8 左右。嗯,结果还是不错的。当然,我们还可以做更多的分析和处理工作,来让我们的分数越来越高。希望你能自己动手,尝试提高分数,相信你会享受这个过程的。