如何计算POS标注器的标签精确率和召回率?

8 投票
1 回答
4941 浏览
提问于 2025-04-16 13:27

我正在使用一些基于规则和统计的词性标注工具,来给一个包含大约5000个句子的语料库标注词性。下面是我测试语料库的一小段,每个单词后面跟着它对应的词性标签,用'/'分隔。

No/RB ,/, it/PRP was/VBD n't/RB Black/NNP Monday/NNP ./.
But/CC while/IN the/DT New/NNP York/NNP Stock/NNP Exchange/NNP did/VBD n't/RB fall/VB apart/RB Friday/NNP as/IN the/DT Dow/NNP Jones/NNP Industrial/NNP Average/NNP plunged/VBD 190.58/CD points/NNS --/: most/JJS of/IN it/PRP in/IN the/DT final/JJ hour/NN --/: it/PRP barely/RB managed/VBD *-2/-NONE- to/TO stay/VB this/DT side/NN of/IN chaos/NN ./.
Some/DT ``/`` circuit/NN breakers/NNS ''/'' installed/VBN */-NONE- after/IN the/DT October/NNP 1987/CD crash/NN failed/VBD their/PRP$ first/JJ test/NN ,/, traders/NNS say/VBP 0/-NONE- *T*-1/-NONE- ,/, *-2/-NONE- unable/JJ *-3/-NONE- to/TO cool/VB the/DT selling/NN panic/NN in/IN both/DT stocks/NNS and/CC futures/NNS ./.

标注完成后,语料库看起来是这样的:

No/DT ,/, it/PRP was/VBD n't/RB Black/NNP Monday/NNP ./. 
But/CC while/IN the/DT New/NNP York/NNP Stock/NNP Exchange/NNP did/VBD n't/RB fall/VB apart/RB Friday/VB as/IN the/DT Dow/NNP Jones/NNP Industrial/NNP Average/JJ plunged/VBN 190.58/CD points/NNS --/: most/RBS of/IN it/PRP in/IN the/DT final/JJ hour/NN --/: it/PRP barely/RB managed/VBD *-2/-NONE- to/TO stay/VB this/DT side/NN of/IN chaos/NNS ./. 
Some/DT ``/`` circuit/NN breakers/NNS ''/'' installed/VBN */-NONE- after/IN the/DT October/NNP 1987/CD crash/NN failed/VBD their/PRP$ first/JJ test/NN ,/, traders/NNS say/VB 0/-NONE- *T*-1/-NONE- ,/, *-2/-NONE- unable/JJ *-3/-NONE- to/TO cool/VB the/DT selling/VBG panic/NN in/IN both/DT stocks/NNS and/CC futures/NNS ./. 

我需要计算标注的准确率(按标签计算的召回率和精确率),因此需要找出每个单词和标签配对的标注错误(如果有的话)。

我想到的方法是遍历这两个文本文件,把它们存储在一个列表中,然后逐个比较这两个列表的元素。

我觉得这个方法有点粗糙,所以想请大家给我一些更好的解决方案。

根据维基百科的解释:

在分类任务中,某个类别的精确率是指被正确标记为正类的项目数量(即真正例)除以被标记为正类的所有项目的总数(即真正例和假正例的总和,假正例是指错误标记为该类的项目)。在这个上下文中,召回率定义为真正例的数量除以实际上属于正类的所有项目的总数(即真正例和假负例的总和,假负例是指没有被标记为正类但应该被标记的项目)。

1 个回答

7

注意,因为每个单词都有一个对应的标签,所以整体的召回率和准确率对于这个任务来说没有意义(它们的值会和准确度相等)。不过,针对每个标签来计算召回率和准确率是有意义的,比如你可以找出DT标签的召回率和准确率。

要一次性高效地处理所有标签,方法和你提到的类似,但可以省去制作列表的步骤。你可以逐行读取每个文件,逐个单词进行比较,直到文件结束。每次比较单词时,最好先确认这两个单词是否相等,而不是假设两个文件是同步的。对于每种标签,你需要保持三个统计数据:真正例、假正例和假负例。如果当前单词的两个标签匹配,就把该标签的真正例总数加一。如果不匹配,就需要把真实标签的假负例总数加一,同时把机器错误选择的标签的假正例总数加一。最后,你可以根据维基百科的公式计算每个标签的召回率和准确率。

我没有测试过这段代码,而且我的Python有点生疏,但这应该能给你一个大概念。我假设文件已经打开,totals这个数据结构是一个字典的字典:

finished = false
while not finished:
    trueLine = testFile.readline()
    if not trueLine: # end of file
        finished = true
    else:
        trueLine = trueLine.split() # tokenise by whitespace
        taggedLine = taggedFile.readline()
        if not taggedLine:
            print 'Error: files are out of sync.'
        taggedLine = taggedLine.split()
        if len(trueLine) != len(taggedLine):
            print 'Error: files are out of sync.'
        for i in range(len(trueLine)):
            truePair = trueLine[i].split('/')
            taggedPair = taggedLine[i].split('/')
            if truePair[0] != taggedPair[0]: # the words should match
                print 'Error: files are out of sync.'
            trueTag = truePair[1]
            guessedTag = taggedPair[1]
            if trueTag == guessedTag:
                totals[trueTag]['truePositives'] += 1
            else:
                totals[trueTag]['falseNegatives'] += 1
                totals[guessedTag]['falsePositives'] += 1

撰写回答