4.3 查询标注器

很多高频词没有NN标记。让我们找出 100 个最频繁的词,存储它们最有可能的标记。然后我们可以使用这个信息作为“查找标注器”(NLTK UnigramTagger)的模型:

  1. >>> fd = nltk.FreqDist(brown.words(categories='news'))
  2. >>> cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news'))
  3. >>> most_freq_words = fd.most_common(100)
  4. >>> likely_tags = dict((word, cfd[word].max()) for (word, _) in most_freq_words)
  5. >>> baseline_tagger = nltk.UnigramTagger(model=likely_tags)
  6. >>> baseline_tagger.evaluate(brown_tagged_sents)
  7. 0.45578495136941344

现在应该并不奇怪,仅仅知道 100 个最频繁的词的标记就使我们能正确标注很大一部分词符(近一半,事实上)。让我们来看看它在一些未标注的输入文本上做的如何:

  1. >>> sent = brown.sents(categories='news')[3]
  2. >>> baseline_tagger.tag(sent)
  3. [('``', '``'), ('Only', None), ('a', 'AT'), ('relative', None),
  4. ('handful', None), ('of', 'IN'), ('such', None), ('reports', None),
  5. ('was', 'BEDZ'), ('received', None), ("''", "''"), (',', ','),
  6. ('the', 'AT'), ('jury', None), ('said', 'VBD'), (',', ','),
  7. ('``', '``'), ('considering', None), ('the', 'AT'), ('widespread', None),
  8. ('interest', None), ('in', 'IN'), ('the', 'AT'), ('election', None),
  9. (',', ','), ('the', 'AT'), ('number', None), ('of', 'IN'),
  10. ('voters', None), ('and', 'CC'), ('the', 'AT'), ('size', None),
  11. ('of', 'IN'), ('this', 'DT'), ('city', None), ("''", "''"), ('.', '.')]

许多词都被分配了一个None标签,因为它们不在 100 个最频繁的词之中。在这些情况下,我们想分配默认标记NN。换句话说,我们要先使用查找表,如果它不能指定一个标记就使用默认标注器,这个过程叫做回退(5)。我们可以做到这个,通过指定一个标注器作为另一个标注器的参数,如下所示。现在查找标注器将只存储名词以外的词的词-标记对,只要它不能给一个词分配标记,它将会调用默认标注器。

  1. >>> baseline_tagger = nltk.UnigramTagger(model=likely_tags,
  2. ... backoff=nltk.DefaultTagger('NN'))

让我们把所有这些放在一起,写一个程序来创建和评估具有一定范围的查找标注器 ,4.1

  1. def performance(cfd, wordlist):
  2. lt = dict((word, cfd[word].max()) for word in wordlist)
  3. baseline_tagger = nltk.UnigramTagger(model=lt, backoff=nltk.DefaultTagger('NN'))
  4. return baseline_tagger.evaluate(brown.tagged_sents(categories='news'))
  5. def display():
  6. import pylab
  7. word_freqs = nltk.FreqDist(brown.words(categories='news')).most_common()
  8. words_by_freq = [w for (w, _) in word_freqs]
  9. cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news'))
  10. sizes = 2 ** pylab.arange(15)
  11. perfs = [performance(cfd, words_by_freq[:size]) for size in sizes]
  12. pylab.plot(sizes, perfs, '-bo')
  13. pylab.title('Lookup Tagger Performance with Varying Model Size')
  14. pylab.xlabel('Model Size')
  15. pylab.ylabel('Performance')
  16. pylab.show()

Images/tag-lookup.png

图 4.2:查找标注器

可以观察到,随着模型规模的增长,最初的性能增加迅速,最终达到一个稳定水平,这时模型的规模大量增加性能的提高很小。(这个例子使用pylab绘图软件包,在4.8讨论过)。