python的詞性標註

許可可可可發表於2020-12-24

詞性標註

詞性標註:在給定的句子中判定每個詞的語法範疇,確定詞性並加以標註的過程。

難點:兼類詞的消歧,未登入詞標註

在某具體的語言環境中,一個詞只能屬於某一類詞性。

詞性標註的特殊問題

  1. 形態標準:不符合漢語劃分;
  2. 意義標準:參考作用;
  3. 分佈標準(功能標準);

詞性標註的方法

  1. 基於規則的詞性標註

  2. 基於機器學習的詞性標註
    無監督學習——聚類方法
    半監督學習——自訓練演算法、多視角演算法、直推式

  3. 基於規則與統計相結合的研究方法
    對句子的初始詞性標註結果,首先規則消歧,再通過統計消歧,並對未登入詞進行此行推測,最後進行人工校對,得到比較正確的標註結果。

  4. 基於感知機的標註方法
    輸入:詞的特徵集
    輸出:標註結果(詞類)

馬爾科夫鏈:將來的狀態只與當前有關,短程依賴。
隱含馬爾可夫鏈HMM
馬爾科夫鏈:描述狀態的轉移,用轉移概率描述;
一般隨機過程:描述狀態與觀察序列間的關係,用觀察值概率描述。

設計簡單標註器

  1. 預設標註器nltk.DefaultTagger

只利用了詞本身的統計資訊。
nltk的評估依據是一個標準測試資料,由人手工標註

import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist

tags = [tag for (word, tag) in brown.tagged_words(categories='news')]
word = FreqDist(tags).max()
# 結果:NN
print(word)

brown_sents = brown.sents(categories='news')
brown_tagged_sents = brown.tagged_sents(categories='news')

dt = nltk.DefaultTagger(word) # 以word作為標註器的輸出,設計標註器
dt.tag(brown_sents[0]) # 對句子brown_sents[0]進行標註

# 結果:0.13089484257215028
print(dt.evaluate(brown_tagged_sents)) # 對標註器進行評估
  1. 正規表示式標註器nltk.RegexpTagger
    利用詞形知識初步提高效能。

定義正則模式:正規表示式之間有一定的次序,前者優先

import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist
import re

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)
]

brown_sents = brown.sents(categories='news')
brown_tagged_sents = brown.tagged_sents(categories='news')

rt = nltk.RegexpTagger(patterns) # 定義正規表示式標註器
rt.tag(brown_sents[0]) # 對句子brown_sents[0]進行標註

# 結果:0.20326391789486245
print(rt.evaluate(brown_tagged_sents)) # 對標註器進行評估
  1. 查詢標註器nltk.UnigramTagger
    利用詞頻知識進一步提高效能。

實現:對高頻詞進行專門標記,找出前N(如100)最高頻詞的最可能標註。

import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist

# 選擇brown語料庫中的詞
fd = nltk.FreqDist(brown.words(categories='news'))
# 獲得brown語料庫中的詞及其標註的分佈
cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news')) # cfd是一個繼承詞典

# 結果:{'AT': 5558, 'AT-TL': 18, 'AT-HL': 4}
print(dict(cfd['the']))
# 單詞詞性AT出現了5888次,詞性AT-TL出現了18次,AT-HL出現了4次

# 獲取高頻的N個詞,並進行詞的標註
N = 100
most_freq_words = [word for (word, num) in fd.most_common(N)]
likely_tags = dict((word, cfd[word].max()) for word in most_freq_words)

brown_sents = brown.sents(categories='news')
brown_tagged_sents = brown.tagged_sents(categories='news')

baseline_tagger = nltk.UnigramTagger(model=likely_tags) # 實現標註器
baseline_tagger.tag(brown_sents[0]) # 標註句子

# 結果:0.45578495136941344
print(baseline_tagger.evaluate(brown_tagged_sents)) # 評估該標註器

隨著詞數增加,標註器效能顯著增加,一般設定3000詞左右較合適。這部分的高頻詞一般是話題無關的。

  1. 組合標註器
    理想的標註流程是:先使用查詢標註器,若沒查到,再使用預設標註器或者正則標註器。
# 之前的程式碼 略

btr = nltk.UnigramTagger(model=likely_tags, backoff=dt) # 查詢標註器和預設標註器組合
btr.tag(brown_sents[0]) # 對句子brown_sents[0]進行標註

# 結果:0.5817769556656125
print(btr.evaluate(brown_tagged_sents)) # 評估該標註器

btr = nltk.UnigramTagger(model=likely_tags, backoff=rt) # 查詢標註器和正則標註器組合
btr.tag(brown_sents[0]) # 對句子brown_sents[0]進行標註

# 結果:0.6498697217415518
print(btr.evaluate(brown_tagged_sents)) # 評估該標註器
  1. 一元Uni-gram 二元Bi-gram標註器
    增加對上下文特性的考慮。

    在標註器的實現過程中,帶標註的語料即是標註器的依據,根據每個詞的標註頻次,選擇最高的作為其標註,這個過程稱為“訓練”。

    一元標註器Unigram Tagging

    siz = 100
    train_sents = brown_tagged_sents[siz:]
    test_sents = brown_tagged_sents[:siz]
    
    ug = nltk.UnigramTagger(train_sents) # 訓練
    
    # 結果:[('the', 'AT'), ('man', 'NN'), ('is', 'BEZ')]
    print(list(ug.tag(['the', 'man', 'is'])))
    # 結果:0.8562610229276896
    print(ug.evaluate(test_sents)) # 評估
    

    二元標註器Bigram Tagging

    bg = nltk.BigramTagger(train_sents) # 訓練
    
    # 結果:[('the', 'AT'), ('man', 'NN'), ('is', 'BEZ')]
    print(list(bg.tag(['the', 'man', 'is'])))
    # 結果:0.1318342151675485
    print(bg.evaluate(test_sents)) # 評估
    

    三元標註為Trigram n元標註為Ngram

    Bigram的問題資料稀疏:被標註的語料遇到新詞,則無法正確標註。

  2. n元組合標註器
    Bigram在單獨使用時標註比例很低。

常用標註器介紹

  1. nltk的詞性標註工具
word_lis = nltk.word_tokenize(str(text1)) # 詞列表的構建
nltk.pos_tag(word_lis) # 詞串標記工具

result = nltk.corpus.nps_chat.tagged_words()# 讀取帶標記的語料庫nps_chat
# 結果:[('now', 'RB'), ('im', 'PRP'), ('left', 'VBD'), ...]
print(result)

# 結果:('fly', 'NN')
print(nltk.tag.str2tuple('fly/NN')) # 字串標註轉換為元組形式
  1. thulac漢語詞性標註工具
import thulac

thu = thulac.thulac()
# 結果:[['從', 'p'], ['繁體', 'n'], ['轉換', 'v'], ['為', 'v'], ['簡體', 'n'], ['。', 'w']]   
print(thu.cut("從繁體轉換為簡體。"))
  1. jieba詞性標註器
import jieba
from jieba import posseg

pos = list(jieba.posseg.cut())

詞性標註器的應用

詞性分佈

在語料庫中,查詢最常見的詞性。

import nltk
from nltk.corpus import brown

brown_news_tagged = brown.tagged_words(categories='news')
tag_fd = nltk.FreqDist(tag for (word, tag) in brown_news_tagged)

# 結果:[('NN', 13162), ('IN', 10616), ('AT', 8893)]
print(tag_fd.most_common(3))

基於詞性標註 研究詞的組合

  1. 雙片語合

查詢often之後的詞。

import nltk
from nltk.corpus import brown

text = brown.words(categories='news')
bitext = nltk.bigrams(text)
# 結果:['ambiguous', ',', 'hear', 'a', 'needs', 'that', 'in', 'enough', 'did', 'acceptable', 'mar', '.', 'obstructed', 'build']
ss = [word for word in bitext]

print([b for (a,b) in ss if a=='often']) # 得到全部緊鄰在often後的詞

bd = brown.tagged_words(categories='news')
bibd = nltk.bigrams(bd)
# 結果:['JJ', ',', 'VB', 'AT', 'VBZ', 'CS', 'IN', 'QLP', 'DOD', 'JJ', 'VB', '.', 'VBD', 'VB']    
print([b[1] for (a,b) in bibd if a[0]=='often']) # 得到的是often後的詞的標註
  1. 三片語合

找到三片語合,中間詞是to,前後都是動詞。

# 之前的程式碼 略

tribd = nltk.trigrams(bd)
lis = [(a[0],b[0],c[0]) for (a,b,c) in tribd if a[1].startswith('V') and c[1].startswith('V') and b[1]=='TO'] # 查詢
# 結果:344
print(len(lis))

相關文章