为了直观地解释这些概念,让我们考虑一个简单的例子,假设我们有一个用于预测邮件是否为垃圾邮件的分类模型,我们的任务是将电子邮件列表分为两类:垃圾邮件或非垃圾邮件。我们将用整数1(或正数)表示垃圾邮件,用0(或负数)表示非垃圾邮件。这里我们有一个包含20个电子邮件标题的数据集,我们将每个数据点通过二元分类模型来获得预测类别,然后将其与实际类别进行比较,分类模型返回以下结果:
准确率(Accuracy):准确率是分类正确的样本数占总样本数的比例。也就是说,它是模型正确预测正类和负类的总次数除以总的预测次数。
准确率=(真正例+真负例)/(真正例+假正例+真负例+假负例)
在我们的例子中,我们有20封邮件,模型正确地识别出了15封邮件的真实类别(不管是垃圾邮件还是非垃圾邮件),那么准确率就是75%。
准确性通常被用作分类性能的衡量标准,因为它计算简单且易于解释,然而在处理正负样本不平衡的数据时,它可能会产生误导。让我们回到我们的数据集来理解这一点,假设分类器没有学习任何内容,只是将所有输出分类为0(不是垃圾邮件),我们将在20个正确分类中得到17个,这意味着85%的极高准确度!显然,我们不能说模型的性能很好,因此必须有一种比单独使用准确度更好的方法来衡量分类模型的性能。在介绍其他指标之前有必要了解一下混淆矩阵。
在我们的例子中,我们将事件(1-垃圾邮件)称为“正”,将事件(0-非垃圾邮件)称为“负”。二分类的混淆矩阵是一个2×2矩阵,其中每一列代表一个类,如下所示:
混淆矩阵将分类结果分为四类:
应用于前面的数据集,我们得到以下值:
我们可以将这些值填充到混淆矩阵中,如下所示:
我们还可以将混淆矩阵映射到我们之前看到的准确率公式,如下所示:
现在我们可以通过这个矩阵了解为什么准确性有时会隐藏不平衡数据集的细微差别,原因是在此类数据集中,真负例(真正的非垃圾邮件)类别占主导地位,削弱了其余类别的影响。因此,即使分类模型在其他三个类别中表现不佳,其准确性仍然看起来不错,掩盖了其缺陷。
精确度(Precision):精确度是在所有被模型预测为正类的样本中,实际上为正类的样本的比例。它反映了模型预测为正类的结果的可信度。在信息检索领域,precision也被称为“查准率”
精确度=真正例/(真正例+假正例)
在我们的例子中,我们有20封邮件,模型预测了4封邮件是垃圾邮件,但实际上只有1封是垃圾邮件,那么精确度就是1/4或25%。
召回率(Recall):召回率是在所有实际为正类的样本中,被模型正确预测为正类的样本的比例。它反映了模型捕获正类样本的能力。在信息检索领域,recall也被称为“查全率”。
召回率=真正例/(真正例+假负例)
在我们的例子中,我们有20封邮件,实际上有3封是垃圾邮件,被模型正确预测为垃圾邮件的有1封,那么召回率就是1/3或33%。
我们应该优先考虑哪个指标——精确率还是召回率?
答案是,这取决于我们任务的性质,让我们看看为什么。
例如,我们有1000封邮件,其中垃圾邮件有100封,仍然是希望预测出其中的垃圾邮件。
如果我们希望precision高,那么在极端情况下,我们只把最最可能是垃圾邮件的那一封邮件,也就是No.1的那一封挑出来,这时候precision高达1/1=100%。但是,Recall相应的就会非常低就只有1/100=1%。
如果我们希望recall高,那么极端情况下,我们只要无脑把所有的样本都预测为垃圾邮件,那么此时我们的recall就可以高达100/100=100%,但是此时precision相应的只有100/1000=10%。
我们发现,如果仅仅看recall或者precision中的一个,有可能会在不知情的情况下走向极端;而Accuracy又会受到不平衡样本的影响。
对于垃圾邮件分类任务,可能更希望避免重要的电子邮件被移入垃圾邮件文件夹,而不是将偶尔的垃圾邮件移入收件箱,因此对于这项任务,我们希望优先考虑精确度而不是召回率。
如何选择:
选择精确率还是召回率取决于具体应用和业务目标。
在某些情况下,你可能需要在精确率和召回率之间找到一个折衷。这时候可以使用F1分数作为综合指标,它结合了精确率和召回率的信息,提供了一个平衡两者的方式。如果精确率和召回率同等重要,那么F1分数是一个很好的选择。但是在某些情况下,可能需要根据具体应用调整对精确率和召回率的权重,这时可以使用F-β分数(一个更一般化的F1分数)来调整精确率和召回率之间的相对重要性。
F1分数:F1分数是精确度和召回率的调和平均值,它同时考虑精确度和召回率,给出一个总体的性能指标。
F1=2*(精确度*召回率)/(精确度+召回率)
如果精确度是25%而召回率是33%,F1分数就是2*(0.25*0.33)/(0.25+0.33)≈0.28或28%。
F1提供了精确率和召回率之间的平衡
在多类别分类问题中,宏平均(MacroAverage)和微平均(MicroAverage)是两种常用的方法来计算整体的精确率、召回率和F1分数。这两种方法考虑了类别不平衡的情况,即不同类别的样本数量可能不同。
在多分类任务中,宏平均是对每个类别独立计算指标,然后取所有类别指标的平均值。
宏平均(MacroAverage)计算方法:
宏平均精确率=(精确率1+精确率2+...+精确率N)/N
宏平均召回率=(召回率1+召回率2+...+召回率N)/N
宏平均F1分数=(F1分数1+F1分数2+...+F1分数N)/N
其中N是类别的数量。
下面通过一个例子来展示如何计算多分类任务中的宏平均精确率、召回率和F1分数。假设我们的任务是将电子商务客户电子邮件列表分类为三个类别之一:发货、退货和跟踪,将分别用整数值0、1和2来表示每个类。
这里我们有一个包含15个电子邮件标题的数据集。我们将每个数据点通过多类分类器来获得预测类别,然后将其与实际类进行比较。
首先,准确率的计算与二分类相同——正确预测的数量除以预测的总数。对于我们的数据集,有10个正确的预测和5个错误的预测,这使我们的准确率为10/15≈67%。
接下来,为了计算精度、召回率和F1,我们将构建混淆矩阵。由于我们有三个类,因此矩阵现在变成了3×3矩阵,每一列代表一个类。应用于我们的数据集,我们得到以下矩阵:
在这个混淆矩阵中,行表示真实的类别,列表示模型的预测类别,对角线上的值是每个类别的真正例(TP)。
首先,我们计算每个类别的精确率和召回率:
对于类别0(Shipping):
对于类别1(Returns):
对于类别2(Tracking):
现在,我们用这些值来计算宏平均指标:
宏平均精确率=(精确率(0)+精确率(1)+精确率(2))/3=(0.75+0.67+0.6)/3≈0.66
宏平均召回率=(召回率(0)+召回率(1)+召回率(2))/3=(0.60+0.80+0.60)/3≈0.67
宏平均F1分数=(F1分数(0)+F1分数(1)+F1分数(2))/3=(0.67+0.73+0.60)/3≈0.66
因此,我们计算得到的多个类别的宏平均F1分数大约为0.66,它代表了模型在所有类别上的平均性能,不考虑类别之间的样本数量不平衡。通过宏平均,我们可以了解模型在所有类别上的整体表现,特别适用于类别平衡的情况或者你想给每个类别同等的重要性。
在多分类任务中,微平均(MicroAverage)用于计算整个数据集的统一精确率和召回率,而不区分不同的类别。
微平均(MicroAverage)计算方法:
微平均精确率=总TP/(总TP+总FP)
微平均召回率=总TP/(总TP+总FN)
微平均F1分数=2*(微平均精确率*微平均召回率)/(微平均精确率+微平均召回率)
下面通过一个例子来展示如何计算多分类任务中的微平均精确率和召回率。我们还是以前面的任务举例:
假设我们的任务是将电子商务客户电子邮件列表分类为三个类别之一:发货、退货和跟踪,将分别用整数值0、1和2来表示每个类。
首先,我们计算每个类别的真正例(TP),假正例(FP)和假负例(FN)。
对于类别0:
类似地,我们可以计算B、C和D的TP、FP和FN。
然后,我们将所有类别的TP、FP和FN合计起来得到总的TP、FP和FN。
总TP=TP(0)+TP(1)+TP(2)
总FP=FP(0)+FP(1)+FP(2)
总FN=FN(0)+FN(1)+FN(2)
使用上面的混淆矩阵数据,我们有:
总TP=3+4+3=10
总FP=1+0+0+2+2+0=5
总FN=0+2+1+0+0+2=5
现在我们可以计算微平均精确率和召回率:
计算得出:
微平均精确率=10/(10+5)≈0.66
微平均召回率=10/(10+5)≈0.66
最后,如果需要计算微平均F1分数,可以使用以下公式:
微平均F1分数=2*(0.66*0.66)/(0.66+0.66)≈0.66
这样,我们得到了微平均精确率、召回率和F1分数,它们反映了模型在整个数据集上的总体性能,不考虑类别间的不平衡。
宏平均和微平均的区别在于它们对不同类别的权重处理。宏平均给予每个类别相同的权重,不论类别的样本数量大小。因此,它可能会受到小类别(样本数量少的类别)的过度影响。微平均则将所有类别的贡献视为等同,无论类别的大小,因此在每个样本对结果有同等贡献时,微平均可能是更好的选择。
通常情况下:
在类别不平衡的数据集中,微平均可能更能反映模型的实际性能,因为它确保了大类别不会对整体的评估指标产生过大影响。
HuggingFace开源的evaluate是一个构建在其Transformers库之上的评估工具库,它提供了一种简单、统一的方式来评估机器学习模型,特别是自然语言处理(NLP)领域的模型。evaluate旨在使评估模型变得更加容易、灵活和可复现。
evaluate库的关键特点包括:
使用evaluate库可以非常方便地对模型进行评估。用户只需要加载相应的指标,并将模型的预测输出以及真实标签传递给评估函数即可获得评估结果。这样做的好处在于,用户无需自己编写评估代码,可以保证评估结果的准确性和可比较性。
使用HuggingFace的evaluate库进行模型评估通常涉及以下步骤:
importevaluateaccuracy_metric=evaluate.load("accuracy")results=accuracy_metric.compute(references=[0,1],predictions=[0,1])print(results)#{'accuracy':1.0}直接运行上面的代码会报错,因为默认情况下evaluate.load("accuracy")会从huggingface下载对应metric评测文件,也从huggingface找到metrics/accuracy/accuracy.py文件,但是在国内无法访问huggingface,所以需要在evaluate.load()方法中指定accuracy.py文件的路径才能运行。
在使用evaluate.load()加载评测脚本时,其中的参数path是计算处理脚本路径,可以是处理脚本路径或包含该脚本的目录(如果该脚本与该目录具有相同的名称),例如./metrics/rouge或./metrics/rouge/rouge.py
下面我将使用evaluate工具对我们前面多分类任务的评估指标,宏平均和微平均进行计算,如下所示:
importevaluateactual=[0,0,0,0,0,1,1,1,1,1,2,2,2,2,2]predicted=[0,0,2,0,2,1,1,1,0,1,1,1,2,2,2]f1_metric=evaluate.load(path="/Users/xiniao/myproject/evaluate/metrics/f1",module_type='metric')results=f1_metric.compute(references=actual,predictions=predicted,average='macro')print(results)#输出结果:{'f1':0.6646464646464646}同时计算精确率、召回率、F1分数二分类
可以直接使用下面的代码计算评估结果:
importevaluateactual=[1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]predicted=[1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0]accuracy_metric=evaluate.load(path="/Users/xiniao/myproject/evaluate/metrics/accuracy",module_type='metric')precision_metric=evaluate.load(path="/Users/xiniao/myproject/evaluate/metrics/precision",module_type='metric')recall_metric=evaluate.load(path="/Users/xiniao/myproject/evaluate/metrics/recall",module_type='metric')f1_metric=evaluate.load(path="/Users/xiniao/myproject/evaluate/metrics/f1",module_type='metric')clf_metrics=evaluate.combine([accuracy_metric,precision_metric,recall_metric,f1_metric])result=clf_metrics.compute(predictions=predicted,references=actual)print(result)#输出结果如下:"""{'accuracy':0.75,'precision':0.25,'recall':0.3333333333333333,'f1':0.28571428571428575}"""多分类
对于多分类任务,我们可以分别计算各个评测指标,然后将结果合并到一下,下面介绍一下使用evaluate工具对我们前面多分类任务的评估指标,宏平均和微平均进行计算。分别用整数值0、1和2来表示每个类,如下所示:
宏平均计算,需要在compute()方法中指定average='macro':