hmm进行英文词性标注
生活随笔
收集整理的這篇文章主要介紹了
hmm进行英文词性标注
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
這里采用的手寫維特比算法進行詞性標注?
我們也可以選擇第三方的庫進行計算
https://github.com/jmschrei/yahmm
?
?
?
import nltk import sys from nltk.corpus import brown """ 做這個之前 首先我們要知道 我們知道什么 要求什么 第一步 我們需要根據 給定的語料庫 進行學習hmm模型的 (A,B,π) A 是狀態轉移矩陣 在我們詞庫之中 就是tag之間轉移的概率矩陣 對整個語料進行統計 P(ti | t{i-1}) = count(t{i-1}, ti) / count(t{i-1}) 計算t(i-1)到 ti的轉移概率 就是ti在t(i-1)后面的個數/ T(i-1)tag的總數 B是每個隱藏狀態到可見狀態的概率分布 就是在tag下出現這個可見狀態的概率 也就是在Tag下出現這個單詞的概率 這個在整個語料庫之中也可以統計 P(wi | ti) = count(wi, ti) / count(ti) 等于 tag1下所有的單詞 /tag的數量的單詞 π 是初始概率 就是在0時刻 statr 到每個tag的概率 這個在語料庫中也可以統計 等于 start-tag1的數量 / 所有start到tag的數量根據語料庫 計算出模型所有的參數 (A,B,π) 就可以利用hmm的模型求解三種問題 1.根據hmm模型 用遍歷算法 求出 發生這個可見狀態鏈條概率是多少 可以求出發生這個可見狀態的可能性是多大2.第2個問題就是我們這里詞性標注要解決的問題 給出一個模型(A,B,π) 可見狀態鏈 也就一句話 求出 隱藏狀態鏈 也就是單詞的詞性 維特比算法 動態規劃求解 也可以用第三方的庫 將參數 (A,b,π)帶入求和 我們這里是自己實現這個算法 求和3。第三種問題這個例子中我們無關 說的是模型的參數(A.B.π)不確定 根據我們出現的可見狀態 不斷調整 求出發生這個可見狀態最大可能性 這個模型的參數是什么 在詞性標注的應用就是 給出一句話 然后給出一個隱藏狀態鏈tag 判斷一下匹配度 給出一句話 求出每個單詞的詞性 """""" 預處理詞庫 這里需要的預處理是 給詞加上開始和結束符合 brown 里面的句子都是自己標注好了的,形式如下:(i.NOUN),(LOVE,VERB),(YOU,NOUN) 我們用 (START,START)(END.END) 的格式做開始和結束的標注 下載語料庫 """ #nltk.download('brown')brown_tags_words=[] for sent in brown.tagged_sents():#加上開頭brown_tags_words.append(("START","START"))#省略tag 只去tag前2個字母brown_tags_words.extend([(tag[:2],word) for (word,tag) in sent])#結尾加上結束符合brown_tags_words.append(("END","END"))print(brown_tags_words[0]) #('START', 'START')""" 詞統計 這里計算的是 模型參數B 這個時候,我們要把我們所有的詞庫中擁有的單詞與tag之間的關系,做個簡單粗暴的統計。也就是我們之前說過的:P(wi | ti) = count(wi, ti) / count(ti)你可以自己一個個的loop全部的corpus,當然,這里NLTK給了我們做統計的工具, (這屬于沒有什么必要的hack,裝起逼來也不X,所以,大家想自己實現,可以去實現,不想的話,就用這里提供的方法) """ # conditional frequency distribution cfd_tagwords = nltk.ConditionalFreqDist(brown_tags_words) # conditional probability distribution cpd_tagwords = nltk.ConditionalProbDist(cfd_tagwords, nltk.MLEProbDist) """ 好,現在我們看看平面統計下來的結果: 可以拿到每個tag到 單詞的概率 也就是可見狀態的分布概率 模型參數B 動詞duck的概率 JJ new的概率 """ print("The probability of an adjective (JJ) being 'new' is", cpd_tagwords["JJ"].prob("new")) print("The probability of a verb (VB) being 'duck' is", cpd_tagwords["VB"].prob("duck")) """ The probability of an adjective (JJ) being 'new' is 0.01472344917632025 The probability of a verb (VB) being 'duck' is 6.042713350943527e-05 """""" 計算模型參數 A 隱藏狀態的轉移矩陣 這里面我們也把start 到各個tag的概率也一起計算了 也就是我們這次統計 計算了 2個參數 一個是A 一個是π初始概率 好,接下來,按照課上講的,還有第二個公式需要計算:P(ti | t{i-1}) = count(t{i-1}, ti) / count(t{i-1})這個公式跟words沒有什么卵關系。它是屬于隱層的馬科夫鏈。所以 我們先取出所有的tag來。 """brown_tags = [tag for (tag, word) in brown_tags_words ] # count(t{i-1} ti) # bigram的意思是 前后兩個一組,聯在一起 cfd_tags= nltk.ConditionalFreqDist(nltk.bigrams(brown_tags)) # P(ti | t{i-1}) cpd_tags = nltk.ConditionalProbDist(cfd_tags, nltk.MLEProbDist)""" 好的,可以看看效果了: """ print("If we have just seen 'DT', the probability of 'NN' is", cpd_tags["DT"].prob("NN")) print( "If we have just seen 'VB', the probability of 'JJ' is", cpd_tags["VB"].prob("DT")) print( "If we have just seen 'VB', the probability of 'NN' is", cpd_tags["VB"].prob("NN")) """ DT 轉移到NN的概率 VB到DT的概率 VB到NN的 概率 If we have just seen 'DT', the probability of 'NN' is 0.5057722522030194 If we have just seen 'VB', the probability of 'JJ' is 0.016885067592065053 If we have just seen 'VB', the probability of 'NN' is 0.10970977711020183 """""" 下面可以根據語料計算出來的Hmm 模型 進行詞性標注求解第2類問題 可以根據維特比算法進行計算 也可以用第三方面實現的庫進行計算 YAhMm進行計算 我們這里采用的是自己實現算法 https://github.com/jmschrei/yahmm 第三方實現庫 """"""一些有趣的結果: 那么,比如, 一句話,"I want to race", 一套tag,"PP VB TO VB"他們之間的匹配度有多高呢?其實就是:P(START) * P(PP|START) * P(I | PP) *P(VB | PP) * P(want | VB) *P(TO | VB) * P(to | TO) *P(VB | TO) * P(race | VB) *P(END | VB) """ prob_tagsequence = cpd_tags["START"].prob("PP") * cpd_tagwords["PP"].prob("I") * \cpd_tags["PP"].prob("VB") * cpd_tagwords["VB"].prob("want") * \cpd_tags["VB"].prob("TO") * cpd_tagwords["TO"].prob("to") * \cpd_tags["TO"].prob("VB") * cpd_tagwords["VB"].prob("race") * \cpd_tags["VB"].prob("END")print( "The probability of the tag sequence 'START PP VB TO VB END' for 'I want to race' is:", prob_tagsequence) #The probability of the tag sequence 'START PP VB TO VB END' for 'I want to race' is: 1.0817766461150474e-14""" 根據hmm進行詞性標注環節 Viterbi 的實現 如果我們手上有一句話,怎么知道最符合的tag是哪組呢? 首先,我們拿出所有獨特的tags(也就是tags的全集) """ distinct_tags = set(brown_tags) sentence = ["I", "want", "to", "race" ] sentlen = len(sentence)""" 接下來,開始維特比:從1循環到句子的總長N,記為i每次都找出以tag X為最終節點,長度為i的tag鏈動態規劃 從第一個開始算 """ viterbi = [ ] """ 同時,還需要一個回溯器:從1循環到句子的總長N,記為i把所有tag X 前一個Tag記下來。 """ backpointer = [ ] first_viterbi = { } first_backpointer = { } for tag in distinct_tags:# don't record anything for the START tagif tag == "START": continuefirst_viterbi[ tag ] = cpd_tags["START"].prob(tag) * cpd_tagwords[tag].prob( sentence[0] )first_backpointer[ tag ] = "START"print(first_viterbi) print(first_backpointer)""" 以上,是所有的第一個viterbi 和第一個回溯點。接下來,把樓上這些,存到Vitterbi和Backpointer兩個變量里去 first_viterbi 這個變量記錄的是 每個tag下是這個單詞的概率 那么動態規劃的原理 這里可以取出 當前概率最大的一個tag作為tag 然后存到backpoint之中 {'CS': 0.0, 'QL': 0.0, 'NP': 1.7319067623793952e-06, 'IN': 0.0, 'AP': 0.0, 'NI': 3.3324520848931064e-07, '(-': 0.0, ')-': 0.0, 'CC': 0.0, 'WD': 0.0, 'END': 0.0, 'NR': 0.0, 'CD': 0.0, '*': 0.0, '(': 0.0, 'DT': 0.0, 'RP': 0.0, 'WQ': 0.0, ':': 0.0, 'WP': 0.0, "''": 0.0, '--': 0.0, 'AT': 0.0, "'": 0.0, 'DO': 0.0, 'PN': 0.0, ',-': 0.0, 'NN': 1.0580313619573935e-06, ')': 0.0, 'AB': 0.0, 'RB': 0.0, 'HV': 0.0, '``': 0.0, '*-': 0.0, ',': 0.0, 'JJ': 0.0, 'FW': 0.0, 'PP': 0.014930900689060006, 'TO': 0.0, 'MD': 0.0, 'EX': 0.0, '.-': 0.0, '.': 0.0, 'UH': 0.0, 'RN': 0.0, 'WR': 0.0, 'VB': 0.0, ':-': 0.0, 'BE': 0.0, 'OD': 0.0} first_backpointer {'CS': 'START', 'QL': 'START', 'NP': 'START', 'IN': 'START', 'AP': 'START', 'NI': 'START', '(-': 'START', ')-': 'START', 'CC': 'START', 'WD': 'START', 'END': 'START', 'NR': 'START', 'CD': 'START', '*': 'START', '(': 'START', 'DT': 'START', 'RP': 'START', 'WQ': 'START', ':': 'START', 'WP': 'START', "''": 'START', '--': 'START', 'AT': 'START', "'": 'START', 'DO': 'START', 'PN': 'START', ',-': 'START', 'NN': 'START', ')': 'START', 'AB': 'START', 'RB': 'START', 'HV': 'START', '``': 'START', '*-': 'START', ',': 'START', 'JJ': 'START', 'FW': 'START', 'PP': 'START', 'TO': 'START', 'MD': 'START', 'EX': 'START', '.-': 'START', '.': 'START', 'UH': 'START', 'RN': 'START', 'WR': 'START', 'VB': 'START', ':-': 'START', 'BE': 'START', 'OD': 'START'} """viterbi.append(first_viterbi) backpointer.append(first_backpointer) #全部存起來 """ 我們可以先看一眼,目前最好的tag是啥: 也就是把第一個單詞所有tag的情況下的概率都算出來 然后取最大值 作為第一個tag的值 """ currbest = max(first_viterbi.keys(), key = lambda tag: first_viterbi[ tag ]) print( "Word", "'" + sentence[0] + "'", "current best two-tag sequence:", first_backpointer[ currbest], currbest) #Word 'I' current best two-tag sequence: START PP""" 就是這樣 我們一個單詞一個單詞往下算 每次都找到最大的那個概率 然后作為tag鏈 序列 好的一些都清晰了我們開始loop: """ for wordindex in range(1, len(sentence)):this_viterbi = { }this_backpointer = { }prev_viterbi = viterbi[-1]for tag in distinct_tags:# START沒有卵用的,我們要忽略if tag == "START": continue# 如果現在這個tag是X,現在的單詞是w,# 我們想找前一個tag Y,并且讓最好的tag sequence以Y X結尾。# 也就是說# Y要能最大化:# prev_viterbi[ Y ] * P(X | Y) * P( w | X)best_previous = max(prev_viterbi.keys(),key = lambda prevtag: \prev_viterbi[ prevtag ] * cpd_tags[prevtag].prob(tag) * cpd_tagwords[tag].prob(sentence[wordindex]))this_viterbi[ tag ] = prev_viterbi[ best_previous] * \cpd_tags[ best_previous ].prob(tag) * cpd_tagwords[ tag].prob(sentence[wordindex])this_backpointer[ tag ] = best_previous# 每次找完Y 我們把目前最好的 存一下currbest = max(this_viterbi.keys(), key = lambda tag: this_viterbi[ tag ])print( "Word", "'" + sentence[ wordindex] + "'", "current best two-tag sequence:", this_backpointer[ currbest], currbest)# 完結# 全部存下來viterbi.append(this_viterbi)backpointer.append(this_backpointer)""" 找END,結束: """# 找所有以END結尾的tag sequence prev_viterbi = viterbi[-1] best_previous = max(prev_viterbi.keys(),key = lambda prevtag: prev_viterbi[ prevtag ] * cpd_tags[prevtag].prob("END"))prob_tagsequence = prev_viterbi[ best_previous ] * cpd_tags[ best_previous].prob("END")# 我們這會兒是倒著存的。。。。因為。。好的在后面 best_tagsequence = [ "END", best_previous ] # 同理 這里也有倒過來 backpointer.reverse()""" 最終:回溯所有的回溯點此時,最好的tag就是backpointer里面的current best """current_best_tag = best_previous for bp in backpointer:best_tagsequence.append(bp[current_best_tag])current_best_tag = bp[current_best_tag]best_tagsequence.reverse() print( "The sentence was:", end = " ") for w in sentence: print( w, end = " ") print("\n") print( "The best tag sequence is:", end = " ") for t in best_tagsequence: print (t, end = " ") print("\n") print( "The probability of the best tag sequence is:", prob_tagsequence)""" Word 'I' current best two-tag sequence: START PP Word 'want' current best two-tag sequence: PP VB Word 'to' current best two-tag sequence: VB TO Word 'race' current best two-tag sequence: IN NN The sentence was: I want to race The best tag sequence is: START PP VB IN NN END The probability of the best tag sequence is: 5.71772824864617e-14 """?
總結
以上是生活随笔為你收集整理的hmm进行英文词性标注的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机之父ppt,24计算机之父童年的故
- 下一篇: this关键字的作用