我正在使用一些基于规则和统计的词性标注器来对一个包含大约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 ./.
我需要计算标注的准确性(按标签的召回率和精确度),因此需要找出每个单词-标签对的标注错误(如果有的话)。
我考虑的方法是遍历这两个文本文件,将它们存储在一个列表中,然后逐元素比较这两个列表。
这种方法对我来说似乎非常粗糙,所以希望你们能建议一些更好的解决方案来解决上述问题。
根据维基百科页面:
在分类任务中,一个类的精确度是真阳性数(即正确标记为属于阳性类的项目数)除以标记为属于阳性类的总元素数(即真阳性和假阳性的总和,后者是错误标记为属于该类的项目)。在这种情况下,召回率被定义为真阳性数除以实际属于阳性类的总元素数(即真阳性和假阴性的总和,后者是未被标记为属于阳性类但应该被标记的项目)。
回答:
请注意,由于每个单词只有一个标签,因此对于这项任务,总体的召回率和精确度得分是没有意义的(它们都将等于准确性度量)。但按标签计算召回率和精确度是有意义的——例如,你可以计算DT标签的召回率和精确度。
一次性为所有标签计算的最有效方法与你建议的方式类似,不过你可以通过跳过列表制作阶段来节省一次数据处理。读取每个文件的一行,逐词比较这两行,然后重复直到文件结束。对于每次单词比较,你可能需要检查单词是否相等以确保数据的完整性,而不是假设两个文件是同步的。对于每种标签,你需要保持三个运行总数:真阳性、假阳性和假阴性。如果当前单词的两个标签匹配,则增加该标签的真阳性总数。如果它们不匹配,你需要增加真实标签的假阴性总数和机器错误选择的标签的假阳性总数。最后,你可以按照维基百科摘录中的公式计算每个标签的召回率和精确度得分。
我没有测试过这段代码,我的Python也有点生疏,但这应该能给你一个思路。我假设文件已经打开,并且totals
数据结构是一个字典的字典:
finished = falsewhile 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