一元标注器unigram tagging
一元标注器利用一种简单的统计算法,对每个标识符分配最有可能的标记。建立一元标注器的技术称为训练。
>>> from nltk.corpus import brown
>>> import nltk
>>> brown_tagged_sents = brown.tagged_sents(categories='news')
>>> brown_sents = brown.sents(categories='news')
>>> unigram_tagger = nltk.UnigramTagger(brown_tagged_sents)
>>> unigram_tagger.tag(brown_sents[2007])
[('Various', 'JJ'), ('of', 'IN'), ('the', 'AT'), ('apartments', 'NNS'), ('are', 'BER'), ('of', 'IN'), ('the', 'AT'), ('terrace', 'NN'), ('type', 'NN'), (',', ','), ('being', 'BEG'), ('on', 'IN'), ('the', 'AT'), ('ground', 'NN'), ('floor', 'NN'), ('so', 'QL'), ('that', 'CS'), ('entrance', 'NN'), ('is', 'BEZ'), ('direct', 'JJ'), ('.', '.')]
>>> unigram_tagger.evaluate(brown_tagged_sents)
0.9349006503968017
通过建立一元标注器进行分类,正确率高达93%,但是如果一个标注器只是记忆它的训练数据,而不试图建立一般的模型,它的效果会更好。但真实的场景要求我们分离训练和测试数据。
>>> size = int(len(brown_tagged_sents)*0.9)
>>> size
4160
>>> train_sents = brown_tagged_sents[:size]
>>> test_sents = brown_tagged_sents[size:]
>>> unigram_tagger = nltk.UnigramTagger(train_sents)
>>> unigram_tagger.evaluate(test_sents)
0.8121200039868434
一般的N-gram标注
当基于unigrams处理语言处理任务时,可使用上下文中的项目。标注时,只考虑当前的标识符,而不考虑其他上下文。给定一个模型,最好为每个词标注其先验的最可能标记。
n-gram是unigram标注器的一般化,它的上下文是当前词和它前面n-1个标识符的词性标记。当n=3时,n-gram标注器将挑选在给定上下文中最有可能的标记。(此时仅考虑当前词的前两个词的标记)
当n越大时,上下文的特异性就会增加,要标注的数据中包含训练数据中不存在的上下文的几率也增大,这被称作数据稀疏问题。因此,在研究结果的精度和覆盖范围之间要有一个权衡(这与信息检索中的精度和召回权衡有关)
解决精度和覆盖范围之间权衡的一个办法是尽可能的使用更精确的算法,但却在跟多时候逊于覆盖范围广的算法。
>>> t0 = nltk.DefaultTagger('NN')
>>> t1 = nltk.UnigramTagger(train_sents,backoff=t0)
>>> t2 = nltk.BigramTagger(train_sents,backoff=t1)
>>> t2.evaluate(test_sents)
0.8452108043456593
>>> t3 = nltk.TrigramTagger(train_sents,backoff=t2)
>>> t3.evaluate(test_sents)
0.843317053722715
>>> t1.evaluate(test_sents)
0.8361407355726104
存储标注器
在大量的语料库训练标注器可能需要花费大量的时间,没有必要重复训练标注器,可将一个训练好的标注器保存到文件为以后重复使用。将标注器t2保存到文件t2.pkl。
>>> from pickle import dump
>>> output = open('t2.pkl','wb')
>>> dump(t2,output,-1)
>>> output.close()
>>> from pickle import load
>>> input = open('t2.pkl','rb')
>>> tagger = load(input)
>>> input.close()
此时可以检验之前保存的标注器是否可以用来标注数据:
>>> text="""the board's action shows what free enterprise is up against in our complex maze of regulatory laws."""
>>> tokens = text.split()
>>> tagger.tag(tokens)
[('the', 'AT'), ("board's", 'NN$'), ('action', 'NN'), ('shows', 'NNS'), ('what', 'WDT'), ('free', 'JJ'), ('enterprise', 'NN'), ('is', 'BEZ'), ('up', 'RP'), ('against', 'IN'), ('in', 'IN'), ('our', 'PP$'), ('complex', 'JJ'), ('maze', 'NN'), ('of', 'IN'), ('regulatory', 'NN'), ('laws.', 'NN')]
n-gram的性能限制是当遇到词性歧义的情况。