我一直在使用NLTK的POS标记器:
...
nltk.pos_tag(nltk.word_tokenize(tfile[i]))
...
但有时我会得到不准确的结果(NN,当我应该得到JJ,等等。我要标记的文本是在一个相当具体的业务领域...我不能自由地在这里说什么域)。不可否认,我不是Python或NLTK的专家(然而,正在研究它),但我想知道是否有某种方法可以提高标记器的准确性。
我认为我理解标记器的工作原理是将给定的文本与预标记文本的语料库进行比较。我的自然倾向是尝试在这个语料库中添加一组我自己的自我标记句子......但我不知道该怎么做。
我非常感谢任何关于如何添加(我更愿意添加到现有的而不是完全开始新的)我自己的文本到语料库的建议,或者如果有人有其他改进的建议为了我的目的,标记器的准确性,我很乐意听到它。
谢谢!
答案 0 :(得分:4)
您可能已经看过GoogleCode book on nltk。我自己一直在慢慢地解决这个问题,虽然我还没有处理POS标记,但是当我觉得自己足够熟练使用这个工具时,这是我最终想要做的事情之一。无论如何,在Chapter 5第2节中,您可以获得以下文本和示例来制作您自己的标记令牌集(向所有人道歉,但我直接从文本中复制):
>>> tagged_token = nltk.tag.str2tuple('fly/NN')
>>> tagged_token
('fly', 'NN')
>>> tagged_token[0]
'fly'
>>> tagged_token[1]
'NN'
接下来是5.2:
我们可以直接从字符串构造标记标记列表。该 第一步是将字符串标记化以访问单个单词/标签 字符串,然后将每个字符串转换为元组(使用 str2tuple())。
>>> sent = '''
... The/AT grand/JJ jury/NN commented/VBD on/IN a/AT number/NN of/IN
... other/AP topics/NNS ,/, AMONG/IN them/PPO the/AT Atlanta/NP and/CC
... Fulton/NP-tl County/NN-tl purchasing/VBG departments/NNS which/WDT it/PPS
... said/VBD ``/`` ARE/BER well/QL operated/VBN and/CC follow/VB generally/RB
... accepted/VBN practices/NNS which/WDT inure/VB to/IN the/AT best/JJT
... interest/NN of/IN both/ABX governments/NNS ''/'' ./.
... '''
>>> [nltk.tag.str2tuple(t) for t in sent.split()]
[('The', 'AT'), ('grand', 'JJ'), ('jury', 'NN'), ('commented', 'VBD'), ('on', 'IN'), ('a', 'AT'), ('number', 'NN'), ... ('.', '.')]
上面的“发送”变量实际上是原始标记文本的样子,通过访问我自己的计算机上的nltk_data目录并查看corpora / brown /中的任何内容来确认,因此您可以使用以下内容编写自己的标记文本这种格式化然后用它构建你自己的一组标记标记。
一旦你设置了自己的标记标记,就可以根据标记的标记设置自己的unigram标记器(从5.5开始):
>>>unigram_tagger = nltk.UnigramTagger(YOUR_OWN_TAGGED_TOKENS)
最后,因为您的标记文本可能是一个非常小的样本(因此不准确),您可以列出一个后备标记器,这样当它失败时,后备就会拯救:
>>> t0 = nltk.UnigramTagger(a_bigger_set_of_tagged_tokens)
>>> t1 = nltk.UnigramTagger(your_own_tagged_tokens, backoff=t0)
最后,你应该研究n-gram差异,bigram,unigram等,这些也包含在前面提到的第5章中。
无论如何,如果你继续阅读第5章,你会看到几种不同的标记文本的方式(包括我最喜欢的:正则表达式标记!)。有很多方法可以做到这一点,太复杂,无法在这样的小帖子中充分覆盖。
警告:我还没有尝试过所有这段代码,所以我提供它作为解决方案,我现在,我自己,试图解决。如果我犯了错误,请帮我纠正。
答案 1 :(得分:2)
“我如何改进NLTK标记”是一个很受欢迎的问题:-)我绝对不会建议你手工制作一个语料库来训练一个标记器。 Taggers需要大量数据才能在新文本上正常工作。
你可以做什么,如果你想付出努力,就是“bootstrap”一个语料库:使用NLTK标记器在你的域中标记一堆文本,手动纠正错误子集(如果它们是可预测的,则更容易),使用结果来训练更好的标记器。你甚至可以重复这个过程,这样你就可以手工清洁更多自己的材料了。您的新标记器仍将基于相对少量的文本,因此您可以添加默认标记器作为@erewok显示的后备。另请参阅this question,其中提出同样的问题。
答案 2 :(得分:0)
正如@erewok指出的那样,使用退避标记是改善事物的好方法。从最准确的开始。如果它无法标记,或计算的概率低于设定的阈值,则尝试下一个(不太准确)的方法。即使最终的“假设它是一个名词”步骤也可以做出可衡量的改进。
像unigram和bigram标签这样的东西通常不那么准确。我建议首先使用朴素贝叶斯标记器(这些在O'Reilly书中有介绍)。这可以使用Unigram标记器或Wordnet标记器(在Wordnet中查找单词,并使用最常见的示例)作为后退标记器。
然后你可以移动到MaxEnt(最大熵)标记器,由于它支持依赖功能,因此被认为比朴素贝叶斯更准确。然而它更慢并且需要更多努力来实现 - 最终结果可能不值得。 NLTK版本也可能有点难以使用。
为了训练这些标记,NLTK确实附带了各种语料库。我不知道你的域名,我不知道它们会有多大用处,但它们包括Penn Treebank的子集,一些特定领域的语料库,各种语言等。看看。
除了O'Reilly的书,我还是会推荐Jacob Perkins Python Text Processing NLTK Cookbook,其中包括这类事情的实际例子。