基於python的自然語言處理 分類和標註詞彙之5.5N-gram標註
一元標註器unigram tagging
一元標註器利用一種簡單的統計演算法,對每個識別符號分配最有可能的標記。建立一元標註器的技術稱為訓練。
>>> fromnltk.corpus import brown
>>> importnltk
>>> 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的效能限制是當遇到詞性歧義的情況。