Python自然語言處理 5 分類和標註詞彙
目標:
(1)什麼是詞彙分類,在自然語言處理中它們如何使用?
(2)對於儲存詞彙和它們的分類來說什麼是好的Python資料結構?
(3)如何自動標註文字中每個詞彙的詞類?
基本技術,包括序列標註,N-gram模型,回退和評估
一 使用詞性標註器
text = nltk.word_tokenize("and now for something completely different")
nltk.pos_tag(text)
[('and', 'CC'),
('now', 'RB'),
('for', 'IN'),
('something', 'NN'),
('completely', 'RB'),
('different', 'JJ')]
同音同義詞,文字轉語音系統通常要進行詞性標註,以便能正確讀課文
二 標註語料庫
#表示已標註的識別符號
tagged_token = nltk.tag.str2tuple('fly/NN')
tagged_token
('fly', 'NN')
#讀取已標註的語料庫
NLTK中包括的若干語料庫已標註了詞性
nltk.corpus.brown.tagged_words()
#簡化的詞性標記集
from nltk.corpus import brown
brown_news_tagged = brown.tagged_words(categories='news',tagset = 'universal')
tag_fd = nltk.FreqDist(tag for (word,tag) in brown_news_tagged)
tag_fd.keys()
[u'ADV',
u'NOUN',
u'ADP',
u'PRON',
#名詞
word_tag_pairs = nltk.bigrams(brown_news_tagged)
list(nltk.FreqDist(a[1] for (a,b) in word_tag_pairs if b[1] == 'N'))
#動詞
wsj = nltk.corpus.treebank.tagged_words(tagset = 'universal')
word_tag_fd = nltk.FreqDist(wsj)
[word+"/"+tag for (word,tag) in word_tag_fd if tag.startswith('V')]
#形容詞和副詞
#未簡化的標記
#探索已標註的語料庫
三 使用Python字典對映詞及其屬性 P206
#索引連結串列VS字典
#PYthon字典
pos = {}
pos['colorless'] = 'ADJ'
pos['ideas'] = 'N'
pos['sleep'] = 'V'
pos['furiously'] = 'ADV'
pos
{'colorless': 'ADJ', 'furiously': 'ADV', 'ideas': 'N', 'sleep': 'V'}
for word in sorted(pos):
print word + ":", pos[word]
#定義字典
#預設字典
#遞增地更新字典
四 自動標註
from nltk.corpus import brown
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories='news')
文字詞彙
#預設標註器
tags = [tag for (word,tag) in brown.tagged_words(categories='news')]
nltk.FreqDist(tags).max()
u'NN'
將所有詞都標註成NN的標註器
raw = 'I do not like green eggs and ham, I do not like them Sam I am!'
tokens = nltk.word_tokenize(raw)
default_tagger = nltk.DefaultTagger('NN')
default_tagger.tag(tokens)
[('I', 'NN'),
('do', 'NN'),
('not', 'NN'),
('like', 'NN'),
評估
default_tagger.evaluate(brown_tagged_sents)
0.13089484257215028
#正規表示式標註器
基於匹配模式分配標記給識別符號,如認為以ed結尾的詞都是動詞過去分詞
patterns = [
(r'.*ing$', 'VBG'), # gerunds
(r'.*ed$', 'VBD'), # simple past
(r'.*es$', 'VBZ'), # 3rd singular present
(r'.*ould$', 'MD'), # modals
(r'.*\'s$', 'NN$'), # possessive nouns
(r'.*s$', 'NNS'), # plural nouns
(r'^-?[0-9]+(.[0-9]+)?$', 'CD'), # cardinal numbers
(r'.*', 'NN') # nouns (default)
]
regexp_tagger = nltk.RegexpTagger(patterns)
regexp_tagger.tag(brown_sents[3])
[(u'``', 'NN'),
(u'Only', 'NN'),
(u'a', 'NN'),
(u'relative', 'NN'),
(u'handful', 'NN'),
評估
regexp_tagger.evaluate(brown_tagged_sents)
0.20326391789486245
#查詢標註器
nltk.UnigramTagger()
**開發已標註語料庫是一個重大的任務,為確保高品質的標註,除了資料,它會產生複雜的工具,文件和實踐.標記集和其他編碼方案不可避免地依賴於一些理論主張,不是所有的理論主張都被共享.然而,語料庫的創作者往往竭盡全力使他們的工作儘可能中立,以最大限度地提高其工作的有效性
fd = nltk.FreqDist(brown.words(categories='news'))
cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news'))
most_freq_words = fd.keys()[:100]
likely_tags = dict((word,cfd[word].max()) for word in most_freq_words)
baseline_tagger = nltk.UnigramTagger(model=likely_tags)
baseline_tagger.evaluate(brown_tagged_sents)
0.005171350717027666
五 N-gram標註
#一元標註器(Unigram Tagging)
from nltk.corpus import brown
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])
[(u'Various', u'JJ'),
(u'of', u'IN'),
(u'the', u'AT'),
(u'apartments', u'NNS'),
(u'are', u'BER'),
#分離訓練和測試資料
90%為訓練資料,10%為測試資料
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.8120203329014253
#一般的N-gram的標註
bigram_tagger = nltk.BigramTagger(train_sents)
bigram_tagger.tag(brown_sents[2007])
[(u'Various', u'JJ'),
(u'of', u'IN'),
(u'the', u'AT'),
(u'apartments', u'NNS'),
bigram_tagger.evaluate(test_sents)
0.10276088906608193
當n越大時,上下文的特異性就會增加,要標註的資料中包含訓練資料中不存在的上下文的機率也增加.這被稱為資料稀疏問題,在NLP中是相當普遍的.因此,研究結果的精度和覆蓋範圍之間需要有一個權衡(這與資訊檢索中的精度/召回權衡有關)
#組合標註器
解決精度和覆蓋範圍之間權衡的一個辦法是儘可能地使用更精確的演算法,但卻在很多時候卻遜於覆蓋範圍更廣的演算法.如組合bigram標註器和unigram標註器和一個預設標註器.
- 嘗試使用bigram標註器標註識別符號
- 如果bigram標準器無法找到標記,嘗試unigram標註器
- 如果unigram標註器也無法找到標記,使用預設標註器
t0 = nltk.DefaultTagger('NN')
t1 = nltk.UnigramTagger(train_sents, backoff=t0) #回退
t2 = nltk.BigramTagger(train_sents, backoff=t1)
t2.evaluate(test_sents)
0.844911791089405
#標註生詞
方法是回退到正規表示式標註器或預設標註器
#儲存標註器
沒有必要重複訓練標註器,可將一個訓練好的標註器儲存到檔案為以後重複使用.將標註器t2儲存到檔案t2.pkl
from cPickle import dump
output = open('t2.pkl', 'wb')
dump(t2, output, -1)
output.close()
from cPickle 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', u'AT'),
("board's", u'NN$'),
('action', 'NN'),
('shows', u'NNS'),
('what', u'WDT'),
('free', u'JJ'),
#效能限制
n-gram標註器效能的上限是什麼?參考trigram標註器.
cfd = nltk.ConditionalFreqDist( ((x[1],y[1],z[0]), z[1]) for sent in brown_tagged_sents for x, y, z in nltk.trigrams(sent))
ambiguous_contexts = [c for c in cfd.conditions() if len(cfd[c]) > 1]
sum(cfd[c].N() for c in ambiguous_contexts) / cfd.N()
調查標註器
test_tags = [tag for sent in brown.sents(categories='editorial') for (word,tag) in t2.tag(sent)]
gold_tags = [tag for (word,tag) in brown.tagged_words(categories='editorial')]
print nltk.ConfusionMatrix(gold_tags, test_tags)
分析標註器效能界限的另一種方式是人工標註者經過商討得到的
#跨句子邊界標註
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories='news')
size = int(len(brown_tagged_sents) * 0.9)
train_sents = brown_tagged_sents[:size]
test_sents = brown_tagged_sents[size:]
t0 = nltk.DefaultTagger('NN')
t1 = nltk.UnigramTagger(train_sents, backoff=t0)
t2 = nltk.BigramTagger(train_sents, backoff=t1)
t2.evaluate(test_sents)
0.844911791089405
六 基於轉換的標註
n-gram標註器存在的一個潛在的問題是n-gram表的大小(或語言模型)。如果將各種語言技術的標註器部署在移動計算裝置上,在模型大小和標註器效能之間取得平衡是很重要的。
第二個問題是關於上下文的。
在本節中,我們利用Brill標註,它是一種歸納標註方法,效能好,使用的模型僅有n-gram標註器的很小一部分
七 如何確定一個詞的分類
形態學線索
句法線索
語義線索
新詞
詞性標記集中的形態學
八 深入閱讀
相關文章
- Python自然語言處理 2 獲得文字語料和詞彙資源Python自然語言處理
- Python自然語言處理 6 學習分類文字Python自然語言處理
- 自然語言處理之序列標註問題自然語言處理
- Python自然語言處理Python自然語言處理
- Python 自然語言處理(基於jieba分詞和NLTK)Python自然語言處理Jieba分詞
- Python自然語言處理 1 語言處理與PythonPython自然語言處理
- 自然語言處理:分詞方法自然語言處理分詞
- 精通Python自然語言處理 4 :詞性標註--單詞識別Python自然語言處理詞性標註
- 自然語言處理工具pyhanlp分詞與詞性標註自然語言處理HanLP分詞詞性標註
- 自然語言處理標註工具——Brat(安裝、測試、使用)自然語言處理
- 自然語言處理之jieba分詞自然語言處理Jieba分詞
- Python自然語言處理 3 處理原始文字Python自然語言處理
- Python自然語言處理實戰(4):詞性標註與命名實體識別Python自然語言處理詞性標註
- 自然語言處理(NLP)自然語言處理
- Python自然語言處理實戰(3):中文分詞技術Python自然語言處理中文分詞
- 精通Python自然語言處理 2 :統計語言建模Python自然語言處理
- 自然語言處理(NLP)系列(一)——自然語言理解(NLU)自然語言處理
- 自然語言處理(NLP)概述自然語言處理
- 自然語言處理NLP(四)自然語言處理
- 精通Python自然語言處理 1 :字串操作Python自然語言處理字串
- 基於機器學習和TFIDF的情感分類演算法,詳解自然語言處理機器學習演算法自然語言處理
- 自然語言處理工具hanlp自定義詞彙新增圖解自然語言處理HanLP圖解
- 詞!自然語言處理之詞全解和Python實戰!自然語言處理Python
- 深度學習、自然語言處理和表徵方法深度學習自然語言處理
- hanlp自然語言處理包的基本使用--pythonHanLP自然語言處理Python
- 《Python自然語言處理實戰》連結表Python自然語言處理
- 精通Python自然語言處理 3 :形態學Python自然語言處理
- Python 自然語言處理(NLP)工具庫彙總Python自然語言處理
- HanLP 自然語言處理 for nodejsHanLP自然語言處理NodeJS
- [譯] 自然語言處理真是有趣!自然語言處理
- 自然語言處理與分析(one)自然語言處理
- NLP自然語言處理中的hanlp分詞例項自然語言處理HanLP分詞
- 自然語言處理中的分詞問題總結自然語言處理分詞
- 中文自然語言處理工具hanlp隱馬角色標註詳解自然語言處理HanLP
- 中國語文(自然語言處理)作業自然語言處理
- Python自然語言處理工具Python自然語言處理
- Python自然語言處理入門Python自然語言處理
- Python自然語言處理實戰(1):NLP基礎Python自然語言處理