日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

维特比算法 python_维特比算法 实现中文分词 python实现

發(fā)布時(shí)間:2023/12/20 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 维特比算法 python_维特比算法 实现中文分词 python实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近我在學(xué)習(xí)自然語言處理,相信大家都知道NLP的第一步就是學(xué)分詞,但分詞≠自然語言處理。現(xiàn)如今分詞工具及如何使用網(wǎng)上一大堆。我想和大家分享的是結(jié)巴分詞核心內(nèi)容,一起探究分詞的本質(zhì)。

(1)、基于前綴詞典實(shí)現(xiàn)高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構(gòu)成的有向無環(huán)圖

什么是DAG(有向無環(huán)圖)?

例如,句子“去北京大學(xué)玩”對應(yīng)的DAG為{0:[0], 1:[1,2,4], 2:[2], 3:[3,4], 4:[4], 5:[5]}。DAG中{0:[0]}就表示0位置對應(yīng)的是詞,就是說0~0,即“去”這個(gè)詞在Dict(詞典庫,里面記錄每個(gè)詞的頻次)中是詞條。DAG中{1:[1,2,4]},就是表示從1位置開始,在1,2,4位置都是詞,就是說1~1、1~2、1~4即“北”“北京”“北京大學(xué)”這三個(gè)也是詞,出現(xiàn)在Dict中。句子“去北京大學(xué)玩”的DAG畢竟比較短可以一眼看出來,現(xiàn)在來了另外一個(gè)句子“經(jīng)常有意見分歧”,如何得到它的DAG呢?這時(shí)候就得通過代碼來實(shí)現(xiàn)了。

Dict= {"經(jīng)常":0.1,"經(jīng)":0.05,"有":0.1, "常":0.001,"有意見":0.1, "歧":0.001,"意見":0.2,"分歧":0.2,"見":0.05,"意":0.05,"見分歧":0.05,"分":0.1}

def DAG(sentence):

DAG = {} #DAG空字典,用來構(gòu)建DAG有向無環(huán)圖

N = len(sentence)

for k in range(N):

tmplist = []

i = k

frag = sentence[k]

while i < N:

if frag in Dict:

tmplist.append(i)

i += 1

frag = sentence[k:i + 1]

if not tmplist:

tmplist.append(k)

DAG[k] = tmplist

return DAG

print(DAG("經(jīng)常有意見分歧"))

輸出:

{0: [0, 1], 1: [1], 2: [2, 4], 3: [3, 4], 4: [4, 6], 5: [5, 6], 6: [6]}

根據(jù)dict及其每個(gè)詞出現(xiàn)的概率,可以得到所有可能出現(xiàn)路徑(分詞情況),如下圖:

DAG的圖表示

只要出現(xiàn)的詞,就可以分,像“經(jīng)常有”這個(gè)詞沒出現(xiàn),就不能把它當(dāng)做單獨(dú)一個(gè)詞分開了,通過運(yùn)行代碼,我們可以得到“經(jīng)常有意見分歧”的DAG

{0: [0, 1], 1: [1], 2: [2, 4], 3: [3, 4], 4: [4, 6], 5: [5, 6], 6: [6]}

,便于直觀理解DAG,我們把問題轉(zhuǎn)化成尋找路徑的過程,就如上圖表示,從開始到結(jié)束,比如我照最上面紅線的路徑走,可以得到[經(jīng)常|有|意見|分歧]的分詞情況,如果把它們每一步的概率值加起來就是該路徑的得分S=0.1+0.1+0.2+0.2=0.6,同理我走其他的路徑[經(jīng)|常|有意見|分歧],它的得分就是S=0.05+.0.001+0.1+0.2=0.351。這就是我們的第一步,通過代碼構(gòu)建出一個(gè)sentence的DAG。

(2)采用動(dòng)態(tài)規(guī)劃查找最大概率路徑,找出基于詞頻的最大切分組合。

通過第一步,得到了DAG,同樣也可以得到每條路徑的得分S,從中找到得分最大的,也就是概率值最大的情況,就是我們要找的分詞情況。如果用遍歷所有路徑的話,找到每個(gè)路徑然后求出每個(gè)S,取出最大的S,當(dāng)然可以得到我們想要的,但比較蠻力。我們可以試著用動(dòng)態(tài)規(guī)劃的思路,維特比算法,直接上圖

維特比算法的順序解法

給每個(gè)節(jié)點(diǎn)編號1~8,開始到結(jié)束,f(a)代表該節(jié)點(diǎn)的所有得分值,每一步單個(gè)的箭頭都有其對應(yīng)的概率值,c(a~b)代表的是a節(jié)點(diǎn)到b節(jié)點(diǎn)的值,如c(1~3)是“經(jīng)常”的概率值,為什么有的節(jié)點(diǎn)如f(6)有三個(gè)值?那是因?yàn)?這個(gè)節(jié)點(diǎn)有三個(gè)箭頭指向它,也就是說有多少個(gè)箭頭指向該節(jié)點(diǎn),該節(jié)點(diǎn)就有多少個(gè)得分值,如分f(3)有2個(gè)值、f(4)有一個(gè)值......。按1~8的順序,計(jì)算出每個(gè)節(jié)點(diǎn)的所有得分值,計(jì)算后面節(jié)點(diǎn)的時(shí)候要用到前面節(jié)點(diǎn)得分值都取(max)最大的,以保證最后計(jì)算到f(8)時(shí)是全局的最大值,例如計(jì)算f(4)中f(3)取的就是0.1。算到最后,我們知道f(8)=f(6) +c(6~8) =0.4+0.2=0.6 (max),接著把f(6)展開,f(8)=f(4) +c(4~6) +c(6~8) ,同理,把所有的f()換成c(),f(8)=c(1~3) +c(3~4) +c(4~6) +c(6~8) 。直到等式右邊沒有f(),c(1~3)、c(3~4)、c(4~6)、c(6~8)分別代表啥各位看圖去吧。

回到開始,假如用蠻力一個(gè)一個(gè)列出所有路徑,不累死也得列的頭暈,用動(dòng)態(tài)規(guī)劃的思想可以把一個(gè)大問題拆分到每一步的小問題,下一步的小問題只需要在之前的小問題上再進(jìn)一步,動(dòng)態(tài)規(guī)劃的思想就像是小問題站巨人肩膀上,然后大問題莫名其妙就解決了。剛說的是從開始到結(jié)束的順序解法,要是從8節(jié)點(diǎn)到1節(jié)點(diǎn)逆序解法怎么解?

維特比算法的逆序解法

發(fā)現(xiàn)沒,最后最大都是0.6=f(1)=c(1~3) +c(3~4) +c(4~6) +c(6~8),而且直接都是看出來了,再一次說明了最大的路徑就是這條路徑。說了這么多,上代碼

sentence ="經(jīng)常有意見分歧"

N=len(sentence)

route={}

route[N] = (0, 0)

DAG={0: [0, 1], 1: [1], 2: [2, 4], 3: [3, 4], 4: [4, 6], 5: [5, 6], 6: [6]}

for idx in range(N - 1, -1, -1):

distance = (((Dict.get(sentence[idx:x + 1]) or 0) + route[x + 1][0], x) for x in DAG[idx])

route[idx] = max(distance)

# 列表推倒求最大概率對數(shù)路徑

# route[idx] = max([ (概率值,詞語末字位置) for x in DAG[idx] ])

# 以idx:(概率最大值,詞語末字位置)鍵值對形式保存在route中)

# route[x+1][0] 表示 詞路徑[x+1,N-1]的最大概率值,

# [x+1][0]即表示取句子x+1位置對應(yīng)元組(概率對數(shù),詞語末字位置)的概率對數(shù)

print(route)

輸出結(jié)果:

{7: (0, 0), 6: (0.001, 6), 5: (0.2, 6), 4: (0.25, 4), 3: (0.4, 4), 2: (0.5, 2), 1: (0.501, 1), 0: (0.6, 1)}

這是一個(gè)自底向上的動(dòng)態(tài)規(guī)劃(逆序的解法),從sentence的最后一個(gè)字開始倒序遍歷每個(gè)分詞方式的得分。然后將得分最高的情況以(概率得分值,詞語最后一個(gè)字的位置)這樣的tuple保存在route中。看route的0: (0.6, 1)中的0.6,不就是我們求到的f(1)的max, 1: (0.501, 1)中的0.501不就是f(2)......后面大家對著看圖找規(guī)律吧。最后小操作一波,就可以把我們要的分詞結(jié)果打印出來了,結(jié)果和手推的是一樣的c(1~3) +c(3~4) +c(4~6) +c(6~8)。

x = 0

segs = []

while x < N:

y = route[x][1] + 1

word = sentence[x:y]

segs.append(word)

x = y

print(segs)

#輸出結(jié)果:['經(jīng)常', '有', '意見', '分歧']

上面只是一些核心的思路,好多地方可以繼續(xù)優(yōu)化的,比如把概率值轉(zhuǎn)換成-log(概率值),目的是為了防止下溢問題,只是我舉例的概率值比較大,如果是一個(gè)超大的Dict,為了保證所有詞的概率之和約等于1,那每個(gè)詞對應(yīng)的概率值會(huì)特別小。

(3)中文分詞以后得攻克的難點(diǎn)

1、分詞的規(guī)范,詞的定義還不明確,沒有一個(gè)公認(rèn)的、權(quán)威的標(biāo)準(zhǔn)。

2、歧義詞的切分。這也從側(cè)面證實(shí)了中華文化博大精深。

3、未登錄的新詞。就是咱們的Dict里沒有的詞,對于3這個(gè)比2對分詞的影響大多了,目前結(jié)巴分詞對此采取的方法是:基于漢字成詞能力的HMM模型,使用維特比算法。

參考:

1、貪心學(xué)院nlp

2、自然語言處理理論與實(shí)戰(zhàn) 唐聃

總結(jié)

以上是生活随笔為你收集整理的维特比算法 python_维特比算法 实现中文分词 python实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。