如何计算多类-多标签分类的精度/召回率?


72

我想知道如何计算多类多标签分类的精度和召回率,即多于两个标签且每个实例可以有多个标签的分类?


1
多标签部分使它变得更加困难,我对此也很感兴趣。我认为这不适用于多标签问题,但根本不信任我。
user798719

1
实际上,所有多标签问题都是多类的,因此您可以在R中使用utiml包,例如在Java中使用Mulan。
阿德里亚诺·里沃利

Answers:


19

另一个用于衡量分类器性能的流行工具是ROC / AUC;这个也有一个多类/多标签扩展名:请参阅[Hand 2001]

[Hand 2001]:将ROC曲线下的面积简单归纳为多个类别的分类问题


它很流行,但可能会出现故障。我不完全相信。 stats.stackexchange.com/questions/93901/...
EngrStudent

3
永远不要更改堆栈溢出!Guy提出了一个问题,投票最多的答案实际上并没有回答他的问题,但指出了其他一些更好的工具/库
ragvri

是的,这个答案怎么会有+20?它甚至不包含单词Precision和Recall。
Simon Dirmeier

如果您考虑透彻,您将意识到AUC实际上捕获了精度和召回率。
oDDsKooL

16

是Coursera论坛主题中有关混淆矩阵和多类精度/召回率测量的一些讨论。

基本思想是计算所有类的所有精度和召回率,然后取它们的平均值以获得单个实数测量值。

混淆矩阵使计算精度和召回类变得容易。

以下是从该线程复制的有关混淆矩阵的一些基本说明:

混淆矩阵是当类别多于2种时对真阳性,真阴性,假阳性和假阴性进行分类的一种方法。它用于计算精度和召回率,因此用于计算多类问题的f1分数。

实际值由列表示。预测值由行表示。

例子:

10个实际为8的训练示例被错误地分类(预测)为5
13个实际为4的训练示例被错误地分类为9

混淆矩阵

厘米=
     0 1 2 3 4 5 6 7 8 9 10
     1 298 2 1 0 1 1 3 1 1 0
     2 0 293 7 4 1 0 5 2 0 0
     3 1 3263 0 8 0 0 3 0 2
     4 1 5 0 261 4 0 3 2 0 1
     5 0 0 10 0 254 3 0 10 2 1
     6 0 4 1 1 4 300 0 1 0 0
     7 1 3 2 0 0 0 264 0 7 1
     8 3 5 3 1 7 1 0 289 1 0
     9 0 1 3 13 1 0 11 1 289 0
    10 0 6 0 1 6 1 2 1 4 304

对于x类:

  • 真正值:对角线位置,cm(x,x)。

  • 误报:x列的总和(无主对角线),sum(cm(:, x))-cm(x,x)。

  • 假负数:第x行的总和(无主对角线),sum(cm(x,:),2)-cm(x,x)。

您可以按照课程公式计算准确性,召回率和F1分数。

对所有类别(带有或不带有加权)进行平均可得出整个模型的值。


2
您的轴已翻转。根据您所写的内容,您的CM应该换位。
Spacey

@Tarantula你为什么这么认为?我认为他是正确的。
shahensha

@shahensha尝试一列,这是错误的。
Spacey

1
与Coursera线程的链接已断开
shark8me

8
我不认为此答案可以解决多标签问题。它适用于多类问题。在多标签问题中,假阳性或假阴性的概念是什么?
user798719

13

对于多标签分类,您有两种方法。首先考虑以下内容。

  • n是示例数。
  • Yi是第示例的地面事实标签分配。ith
  • xi是第示例。ith
  • h(xi)是第示例的预测标签。ith

基于示例

指标以每个数据点的方式计算。对于每个预测标签,仅计算其得分,然后将这些得分汇总到所有数据点上。

  • 精度= ,预测的正确率之比。分子找出预测向量中有多少个标签与基本事实有共同点,并且该比率会计算实际有多少个预测真实标签在基本事实中。1ni=1n|Yih(xi)||h(xi)|
  • 回想= ,预测有多少实际标签的比率。分子找到预测向量中与地面实数有共同点的标记(如上所述),然后找到与实际标记数的比率,从而得到预测的实际标记的比例。1ni=1n|Yih(xi)||Yi|

还有其他指标。

基于标签

在这里,事情是按标签进行的。对于每个标签,计算指标(例如,精度,召回率),然后将这些基于标签的指标进行汇总。因此,在这种情况下,最终需要像在二进制分类中一样(因为每个标签都有一个二进制赋值),为整个数据集计算每个标签的精度/召回率。

简单的方法是呈现一般形式。

这只是标准多类等效项的扩展。

  • 宏平均1qj=1qB(TPj,FPj,TNj,FNj)

  • 微观平均B(j=1qTPj,j=1qFPj,j=1qTNj,j=1qFNj)

此处仅是第标签的真实正计数,假正计数,真负计数和假负计数。 Ĵ ħTPj,FPj,TNj,FNjjth

这里代表任何基于度量的混淆矩阵的。在您的情况下,您将插入标准精度并调用公式。对于宏平均值,请传递每个标签计数,然后求和;对于微观平均值,请先对计数进行平均值,然后应用度量函数。B

你可能有兴趣去看看到了MULT标签指标的代码在这里,该包的一部分mldr[R 。您可能也有兴趣研究Java多标签库MULAN

这是一篇介绍不同指标的好论文: 多标签学习算法综述


如果您能像某些维基百科参考一样提供有关您编写的度量标准真实性的参考,那就太好了。你提到的参考文献的指标或研究论文的编码部分..
hacker315

2
答案的末尾已经链接了一篇评论文章(《多标签学习算法评论》)ieeexplore.ieee.org/document/6471714。这些是实现所依据的文献中众所周知的指标。我不确定如何证明真实性。
phoxis

8

我不知道多标签部分,但对于mutli-class分类,这些链接将为您提供帮助

链接说明了如何构建混淆矩阵,可用于计算每个类别的精度和召回率

并且此链接说明了如何计算micro-f1和macro-f1度量来整体评估分类器。

希望您觉得有用。


4
关键点是:有多种可能的有效方法来计算这些指标(例如,微型F1与宏F1),因为有多种方法可以定义正确的内容。这取决于您的申请和有效性标准。
杰克·坦纳

艾哈迈德:谢谢您的链接!@JackTanner也许对此有参考(对于多类多标签分类)?
Vam 2012年

1
@MaVe,对不起,没有链接。这仅仅是根据个人经验。您只需考虑要构成什么(例如,真正的肯定和错误的肯定)就可以到达目的地。
Jack Tanner 2012年

4
第一次链接死亡
Nikana Reklawyks

1

该链接对我有帮助。.https ://www.youtube.com/watch?v=HBi- P5j0Kec我希望它也能对您有所帮助

说分布如下

    A   B   C   D
A   100 80  10  10
B   0    9   0   1
C   0    1   8   1
D   0    1   0   9

A的精度为

P(A)= 100/100 + 0 + 0 +0 = 100

P(B)= 9/9 + 80 + 1 + 1 = 9/91 psst ...本质上取类的真实正值,然后除以行中的列数据

召回将是

R(A)= 100 / 100+ 80 + 10 + 10 = 0.5

R(B)= 9 / 9+ 0 + 0 + 1 = 0.9

psst ...本质上是类的真实肯定,然后按行数据除以列

获得所有值后,取宏观平均值

平均(P)= P(A)+ P(B)+ P(C)+ P(D)/ 4

平均(R)= R(A)+ R(B)+ R(C)+ R(D)/ 4

F1 = 2 * avg(P)* avg(R)/ avg(P)+ avg(R)


0

在哈佛大学cs205.org上查看这些幻灯片。一旦到达“错误度量”部分,就可以讨论多类设置(例如,一对多或一对一)和混淆矩阵中的精度和召回率。混淆矩阵是您真正想要的。

仅供参考,在Python软件包scikits.learn中,内置了一些方法,可以根据经过多类数据训练的分类器自动计算诸如混淆矩阵之类的东西。它可能也可以直接为您计算精确调用图。值得一看。


4
不幸的是,幻灯片的链接已死,我可以在其他地方找到这些幻灯片。
f3lix 2012年

当他们在今年的课程中参加那场演讲时,它将会得到补充。如果我可以将PDF复制到永久链接位置,则可以,但是不能这样做,因此定期中断是不可避免的,并且没有其他地方可以找到注释,它们是针对该课程的。
2012年



0

与一般情况完全相同,使用set:

http://en.wikipedia.org/wiki/F1_score

http://en.wikipedia.org/wiki/Precision_and_recall

以下是简单的Python函数,正是这些函数可以做到这一点:

def precision(y_true, y_pred):
    i = set(y_true).intersection(y_pred)
    len1 = len(y_pred)
    if len1 == 0:
        return 0
    else:
        return len(i) / len1


def recall(y_true, y_pred):
    i = set(y_true).intersection(y_pred)
    return len(i) / len(y_true)


def f1(y_true, y_pred):
    p = precision(y_true, y_pred)
    r = recall(y_true, y_pred)
    if p + r == 0:
        return 0
    else:
        return 2 * (p * r) / (p + r)


if __name__ == '__main__':
    print(f1(['A', 'B', 'C'], ['A', 'B']))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.