天天看点

聊聊机器学习分类问题常用的评价指标

作者:新语数据故事汇

一、 混淆矩阵

在机器学习领域,混淆矩阵(Confusion Matrix),又称为「可能性矩阵」或「错误矩阵」。混淆矩阵是可视化工具,特别用于监督学习,在无监督学习一般叫做匹配矩阵。在图像精度评价中,主要用于比较分类结果和实际测得值,可以把分类结果的精度显示在一个混淆矩阵里面。

混淆矩阵的结构一般如下图表示

聊聊机器学习分类问题常用的评价指标

混淆矩阵表达的含义:

TP(True Positive) :将正类预测为正类数,真实为0,预测为0

FN(False Negative):将正类预测为负类数,真实为0,预测为1

FP(False Positive) :将负类预测为正类数,真实为1,预测为0

TN(True Negative) :将负类预测为负类数,真实为1,预测为1

聊聊机器学习分类问题常用的评价指标

该矩阵常用于易于理解的二分类问题,但通过向混淆矩阵添加更多行和列,也可轻松应用于多分类问题。

举例:如有150个样本数据,预测为类I,类II,类III 各为50个。分类结束后得到的混淆矩阵为:

聊聊机器学习分类问题常用的评价指标

每一行之和表示该类别的真实样本数量,每一列之和表示被预测为该类别的样本数量。

第1行第1列中的43表示有43个实际归属第一类的实例被预测为第一类,同理,第1行第2列的2表示有2个实际归属为第一类的实例被错误预测为第二类。

混淆矩阵是对分类问题预测结果的总结。使用计数值汇总正确和不正确预测的数量,并按每个类进行细分,这是混淆矩阵的关键所在。

混淆矩阵显示了分类模型的在进行预测时会对哪一部分产生混淆。它不仅可以让您了解分类模型所犯的错误,更重要的是可以了解哪些错误类型正在发生。正是这种对结果的分解克服了仅使用分类准确率所带来的局限性。

二、分类指标

从混淆矩阵当中,可以得到更高级的分类指标:Accuracy(精确率),Precision(正确率或者准确率),Recall(召回率),Specificity(特异性),Sensitivity(灵敏度)。

2.1 精确率(Accuracy)

精确率是最常用的分类性能指标。可以用来表示模型的精度,即模型识别正确的个数/样本的总个数。一般情况下,模型的精度越高,说明模型的效果越好。

Accuracy = (TP+TN)/(TP+FN+FP+TN)

2.2 正确率或者准确率(Precision)

又称为查准率,表示在模型识别为正类的样本中,真正为正类的样本所占的比例。一般情况下,查准率越高,说明模型的效果越好。

Precision = TP/(TP+FP)

2.3 召回率(Recall)

召回率又称为查全率,召回率表现出在实际正样本中,分类器能预测出多少。

Recall(召回率)= Sensitivity(敏感指标,True Positive Rate,TPR)= 查全率

表示的是,模型正确识别出为正类的样本的数量占总的正类样本数量的比值。一般情况下,Recall越高,说明有更多的正类样本被模型预测正确,模型的效果越好。

Recall = TP/(TP+FN)

查准率和查全率是一对矛盾的指标。一般来说,查准率高时,查全率往往偏低;当查全率高时,查准率往往偏低。

2.4 精确率(Accuracy)和正确率(Precision)的区别

精确率(Accuracy),不管是哪个类别,只要预测正确,其数量都放在分子上,而分母是全部数据量,说明这个精确率是对全部数据的判断。

而正确率(Precision)在分类中对应的是某个类别,分子是预测该类别正确的数量,分母是预测为该类别的全部数量。

即:Accuracy是对分类器整体上的精确率的评价,而Precision是分类器预测为某一个类别的精确评价。

2.5 Specificity(特异性)

特异性指标,表示的是模型识别为负类的样本的数量,占总的负类样本数量的比值。负正类率(False Positive Rate, FPR),计算公式为:

FPR=FP/(TN+FP)

计算的是模型错识别为正类的负类样本占所有负类样本的比例,一般越低越好。

Specificity = 1 - FPR

2.6 Fβ_Score

Fβ的物理意义就是将正确率和召回率的一种加权平均,在合并的过程中,召回率的权重是正确率的β倍。

F1分数认为召回率和正确率同等重要,F2分数认为召回率的重要程度是正确率的2倍,而F0.5分数认为召回率的重要程度是正确率的一半。比较常用的是F1分数(F1 Score),是统计学中用来衡量二分类模型精确度的一种指标。

F1_Score:数学定义为 F1分数,又称为平衡F分数(Balanced Score),它被定义为正确率和召回率的调和平均数。在 β=1 的情况,F1-Score的值是从0到1的,1是最好,0是最差。

因此我们知道,计算Precision,Recall,Specificity等只是计算某一分类的特性,而Accuracy和F1-Score是判断分类模型总体的标准。

三、ROC 曲线

聊聊机器学习分类问题常用的评价指标

横坐标 :1-Specificity,伪正类率(False positive rate,FPR),预测为正但实际为负的样本占所有负例样本的比例。

纵坐标:Sensitivity,真正类率(True positive rate,TPR),预测为正且实际为正的样本占所有正例样本 的比例。

在一个二分类模型中,假设采用逻辑回归分类器,其给出针对每个实例为正类的概率,那么通过设定一个阈值如0.6,概率大于等于0.6的为正类,小于0.6的为负类。对应的就可以算出一组(FPR,TPR),在平面中得到对应坐标点。随着阈值的逐渐减小,越来越多的实例被划分为正类,但是这些正类中同样也掺杂着真正的负实例,即TPR和FPR会同时增大。阈值最大时,对应坐标点为(0,0),阈值最小时,对应坐标点(1,1)。

如下面这幅图,(a)图中实线为ROC曲线,线上每个点对应一个阈值。

聊聊机器学习分类问题常用的评价指标

① 理想情况下,TPR应该接近1,FPR应该接近0。ROC曲线上的每一个点对应于一个threshold,对于一个分类器,每个threshold下会有一个TPR和FPR。比如Threshold最大时,TP=FP=0,对应于原点;Threshold最小时,TN=FN=0,对应于右上角的点(1,1)。

② P和N得分不作为特征间距离d的一个函数,随着阈值theta增加,TP和FP都增加。

聊聊机器学习分类问题常用的评价指标

3.1 如何画ROC曲线

对于一个特定的分类器和测试数据集,显然只能得到一个分类结果,即一组FPR和TPR结果,而要得到一个曲线,我们实际上需要一系列FPR和TPR的值,这又是如何得到的呢?我们先来看一下Wikipedia上对ROC曲线的定义:

In signal detection theory, a receiver operating characteristic (ROC), or simply ROC curve, is a graphical plot which illustrates the performance of a binary classifier system as its discrimination threshold is varied.

问题在于"as its discrimination threashold is varied"。如何理解这里的"discrimination threashold"呢?我们忽略了分类器的一个重要功能"概率输出",即表示分类器认为某个样本具有多大的概率属于正样本(或负样本)。通过更深入地了解各个分类器的内部机理,我们总能想办法得到一种概率输出。通常来说,是将一个实数范围通过某个变换映射到(0,1)区间。

假如我们已经得到了所有样本的概率输出(属于正样本的概率),现在的问题是如何改变"discrimination threashold"?我们根据每个测试样本属于正样本的概率值从大到小排序。下图是一个示例,图中共有20个测试样本,"Class"一栏表示每个测试样本真正的标签(p表示正样本,n表示负样本),"Score"表示每个测试样本属于正样本的概率。

聊聊机器学习分类问题常用的评价指标

接下来,我们从高到低,依次将"Score"值作为阈值threshold,当测试样本属于正样本的概率大于或等于这个threshold时,我们认为它为正样本,否则为负样本。举例来说,对于图中的第4个样本,其"Score"值为0.6,那么样本1,2,3,4都被认为是正样本,因为它们的"Score"值都大于等于0.6,而其他样本则都认为是负样本。每次选取一个不同的threshold,我们就可以得到一组FPR和TPR,即ROC曲线上的一点。这样一来,我们一共得到了20组FPR和TPR的值,将它们画在ROC曲线的结果如下图:

聊聊机器学习分类问题常用的评价指标

当我们将threshold设置为1和0时,分别可以得到ROC曲线上的(0,0)和(1,1)两个点。将这些(FPR,TPR)对连接起来,就得到了ROC曲线。当threshold取值越多,ROC曲线越平滑。

其实,我们并不一定要得到每个测试样本是正样本的概率值,只要得到这个分类器对该测试样本的"评分值"即可(评分值并不一定在(0,1)区间)。评分越高,表示分类器越肯定地认为这个测试样本是正样本,而且同时使用各个评分值作为threshold。我认为将评分值转化为概率更易于理解一些。

四、AUC

4.1 AUC 值的计算

AUC (Area Under Curve) 被定义为ROC曲线下的面积,显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围一般在0.5和1之间。使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。

AUC的计算有两种方式,梯形法和ROC AUCH法,都是以逼近法求近似值,具体见wikipedia。

4.2 AUC 意味着什么

那么AUC值的含义是什么呢?根据(Fawcett, 2006),AUC的值的含义是:

The AUC value is equivalent to the probability that a randomly chosen positive example is ranked higher than a randomly chosen negative example.

这句话有些绕,我尝试解释一下:首先AUC值是一个概率值,当你随机挑选一个正样本以及一个负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值。当然,AUC值越大,当前的分类算法越有可能将正样本排在负样本前面,即能够更好的分类。

从AUC判断分类器(预测模型)优劣的标准:

AUC = 1,是完美分类器,采用这个预测模型时,存在至少一个阈值能得出完美预测。绝大多数预测的场合,不存在完美分类器。

0.5< AUC <1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。

AUC = 0.5,跟随机猜测一样(例:丢铜板),模型没有预测价值。

AUC <0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测。

简单说:AUC值越大的分类器,正确率越高。

三种 AUC 值示例:

聊聊机器学习分类问题常用的评价指标

五、为什么使用 ROC 曲线

既然已经这么多评价标准,为什么还要使用ROC和AUC呢?因为ROC曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。下图是ROC曲线和Precision-Recall曲线的对比:

聊聊机器学习分类问题常用的评价指标

为什么还要使用ROC和AUC呢?因为ROC曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。ROC和Precision-Recall

在上图中,(a)和(c)为ROC曲线,(b)和(d)为Precision-Recall曲线。(a)和(b)展示的是分类其在原始测试集(正负样本分布平衡)的结果,(c)和(d)是将测试集中负样本的数量增加到原来的10倍后,分类器的结果。可以明显的看出,ROC曲线基本保持原貌,而Precision-Recall曲线则变化较大。

六、 动手实验

依然用我们最熟悉的Iris数据集,分析探索工具依然用我们的数据科学/分析利器SmartNoteBook。

Iris数据集是常用的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一类多重变量分析的数据集。

数据集包含150个数据样本,分为3类,每类50个数据,每个数据包含4个属性。可通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类。

数据导入和准备:

# 导入需要的包
import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle
from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score
from numpy import interp
%matplotlib inline


# 获取数据集,这里我们方便起见只导入两种分类
iris = datasets.load_iris()
X = iris.data[50:150]
y = iris.target[50:150]


# 增加样本记录的数量(将数量翻6翻)
for i in range(6):
    X=np.append(X,X,axis=0)
    y=np.append(y,y,axis=0)           

为数据集增加一些噪音:

random_state = np.random.RandomState(2022)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 32 )]
for i in range(4):
    X[:,i]=X[:,i]+ random_state.randn(1,n_samples )[0]           

查看数据集的形状:

X.shape           

(25600, 36)

标签二值化:

y = label_binarize(y, classes=[0, 1])
n_classes = y.shape[1]           

训练模型并预测:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3,random_state=0)
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True))
y_score = classifier.fit(X_train, y_train).decision_function(X_test)
y_pred = classifier.predict(X_test)           

计算准确率、精确率、召回率、f1_score:

print ('accuracy is %s'% accuracy_score(y_test, y_pred))
print('precision is %s'% classifier.score(X_train, y_train))
print ('recall is %s'% recall_score(y_test, y_pred, average='macro'))
print ('f1-score is %s'% f1_score(y_test, y_pred, average='macro') )           

accuracy is 0.7516927083333333

precision is 0.7500558035714285

recall is 0.7516944913982669

f1-score is 0.7516926704446416

计算并展示混淆矩阵:

# 计算混淆矩阵
from sklearn import metrics
iris_confusion_matrix = metrics.confusion_matrix(y_test,y_pred)
iris_confusion_matrix           
# 直观展示混淆矩阵
from pyecharts import options as opts
from pyecharts.charts import HeatMap


x=['versicolor','virginica']
y=['virginica','versicolor']
i=0
value=[]
for m in iris_confusion_matrix:
    j=0
    for v in m:
       value.append([i,1-j,int(v)])
       j=j+1
    i=i+1
value


c = (
    HeatMap()
    .add_xaxis(x)
    .add_yaxis(
        "",
        y,
        value,
        label_opts=opts.LabelOpts(is_show=True, position="inside"),
    )
    .set_global_opts(
        xaxis_opts=opts.AxisOpts(position='top',name="预测值",name_gap = 35,name_location = 'center'),
        yaxis_opts=opts.AxisOpts(name="真实值",name_gap = 35,name_location = 'center',axislabel_opts=opts.LabelOpts(rotate=90)),
        title_opts=opts.TitleOpts(title="混淆矩阵"),
        visualmap_opts=opts.VisualMapOpts(is_show=False,
                min_ = 0,
                max_ = 5000,
                range_color = ['#0d243b','#053b70'],
                )
    )
)
c.render_notebook()           
聊聊机器学习分类问题常用的评价指标

绘制ROC曲线:

fpr = dict()
tpr = dict()
roc_auc = dict()


fpr, tpr, _ = roc_curve(y_test, y_score)
roc_auc = auc(fpr, tpr)


plt.figure(dpi=100,figsize=(8,6))


plt.plot(fpr, tpr, color=color, lw=1.2) 
plt.plot([0, 1], [0, 1], 'k--', lw=1.2)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc="lower right")
plt.show()           
聊聊机器学习分类问题常用的评价指标

《新语数据故事汇,数说新语》 科普数据科学、讲述数据故事,深层次挖掘数据价值。欢迎各位朋友投稿!

微信号|SnbDataStory

《新语数据故事汇,数说新语》

继续阅读