2

我一直在使用 NLTK 的 POS 标记器:

...
nltk.pos_tag(nltk.word_tokenize(tfile[i]))
...

但有时我会得到不准确的结果(NN 当我应该得到 JJ 时,等等。我要标记的文本是在一个相当具体的业务领域内......我不太自由地说这里是什么领域)。诚然,我不是 Python 或 NLTK 的专家(但是正在研究它),但我想知道是否有一些方法可以提高标记器的准确性。

我想我理解标记器通过将提供给它的文本与预先标记的文本语料库进行比较来工作。我的自然倾向是尝试将一组我自己的自我标记句子添加到这个语料库中……但我不知道该怎么做。

我非常感谢有关如何将我自己的文本添加到语料库(我更愿意添加到现有文本而不是完全开始新文本)的任何建议,或者如果有人对提高标注器的准确性有其他建议出于我的目的,我很想听听。

谢谢!

4

3 回答 3

4

您可能已经看过关于 nltk 的 GoogleCode book。我自己一直在非常缓慢地完成它,虽然我还没有处理 POS 标记,但当我觉得自己足够熟练使用该工具时,这是我最终想做的事情之一。无论如何,在第 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/ 中的任何内容来确认的那样,因此您可以使用这种格式编写自己的标记文本和然后用它构建你自己的一组标记令牌。

设置好自己的标记标记后,您应该能够根据标记标记(从 5.5 开始)设置自己的 unigram 标记器:

>>>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 章,您将看到几种不同的文本标记方法(包括我最喜欢的:正则表达式标记器!)。有很多方法可以做到这一点,而且过于复杂,无法在像这样的小帖子中充分涵盖。

警告购买者:我还没有尝试过所有这些代码,所以我提供它作为我目前正在尝试解决的解决方案。如果我犯了错误,请帮助我纠正它们。

于 2012-10-22T20:03:00.820 回答
2

“我如何改进 NLTK 标注器”是一个流行的问题 :-) 我绝对不建议您手工制作语料库来训练标注器。标注器需要大量数据才能在新文本上正常工作。

如果您想努力,您可以做的是“引导”语料库:使用 NLTK 标记器标记您域中的一堆文本,手动纠正子集中的错误(如果它们是可预测的,则更容易),使用结果来训练更好的标注器。你甚至可以重复这个过程,这样你就可以手工清洁更多的自己的材料。您的新标记器仍将基于相对少量的文本,因此您可以添加默认标记器作为@erewok 显示的后备。另请参阅this question,它提出了同样的问题。

于 2012-10-30T22:50:28.823 回答
0

正如@erewok 所指出的,使用退避标记器是改进事物的好方法。从最准确的开始。如果它无法标记,或者计算出的概率低于设定的阈值,则尝试下一种(不太准确)方法。即使是最后的“假设它是一个名词”步骤也可以做出可衡量的改进。

unigram 和 bigram 标记器之类的东西通常不是那么准确。我建议首先从朴素贝叶斯标记器开始(这些在 O'Reilly 书中都有介绍)。这可以使用 Unigram 标记器或 Wordnet 标记器(在 Wordnet 中查找单词,并使用最常见的示例)作为回退标记器。

然后,您可以使用 MaxEnt(最大熵)标记器,该标记器被认为比朴素贝叶斯更准确,因为它支持依赖特征。然而,它速度较慢并且需要更多的努力来实现——最终结果可能不值得。NLTK 版本也可能有点难以使用。

为了训练这些标注器,NLTK 提供了各种语料库。对您的领域一无所知,我不知道它们会有多大用处,但它们包括 Penn Treebank 的一个子集、一些特定领域的语料库、各种语言等。看一看。

除了 O'Reilly 的书外,我还推荐Jacob Perkins Python 文本处理 NLTK Cookbook,其中包含此类事物的实际示例。

于 2012-10-23T12:50:58.693 回答