c 實現卷積碼編碼和維特比解碼 演算法實現分詞

2021-10-13 18:35:41 字數 2967 閱讀 3229

現如今分詞工具及如何使用網上一大堆。我想和大家分享的是結巴分詞核心內容,一起**分詞的本質。

(1)、基於字首詞典實現高效的詞圖掃瞄,生成句子中漢字所有可能成詞情況所構成的有向無環圖

什麼是dag(有向無環圖)?

例如,句子「去北京大學玩」對應的dag為。dag中就表示0位置對應的是詞,就是說0~0,即「去」這個詞在dict(詞典庫,裡面記錄每個詞的頻次)中是詞條。dag中,就是表示從1位置開始,在1,2,4位置都是詞,就是說1~1、1~2、1~4即「北」「北京」「北京大學」這三個也是詞,出現在dict中。句子「去北京大學玩」的dag畢竟比較短可以一眼看出來,現在來了另外乙個句子「經常有意見分歧」,如何得到它的dag呢?這時候就得通過**來實現了。

dict及其每個詞出現的概率

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

dag的圖表示

只要出現的詞,就可以分,像「經常有」這個詞沒出現,就不能把它當做單獨乙個詞分開了,通過執行**,我們可以得到「經常有意見分歧」的dag,便於直觀理解dag,我們把問題轉化成尋找路徑的過程,就如上圖表示,從開始到結束,比如我照最上面紅線的路徑走,可以得到[經常|有|意見|分歧]的分詞情況,如果把它們每一步的概率值加起來就是該路徑的得分s=0.1+0.1+0.2+0.2=0.6,同理我走其他的路徑[經|常|有意見|分歧],它的得分就是s=0.05+.0.001+0.1+0.2=0.351。這就是我們的第一步,通過**構建出乙個sentence的dag。

(2)採用動態規劃查詢最大概率路徑,找出基於詞頻的最大切分組合。

通過第一步,得到了dag,同樣也可以得到每條路徑的得分s,從中找到得分最大的,也就是概率值最大的情況,就是我們要找的分詞情況。如果用遍歷所有路徑的話,找到每個路徑然後求出每個s,取出最大的s,當然可以得到我們想要的,但比較蠻力。我們可以試著用動態規劃的思路,維特比演算法,直接上圖

維特比演算法的順序解法

給每個節點編號1~8,開始到結束,f(a)代表該節點的所有得分值,每一步單個的箭頭都有其對應的概率值,c(a~b)代表的是a節點到b節點的值,如c(1~3)是「經常」的概率值,為什麼有的節點如f(6)有三個值?那是因為6這個節點有三個箭頭指向它,也就是說有多少個箭頭指向該節點,該節點就有多少個得分值,如分f(3)有2個值、f(4)有乙個值......。按1~8的順序,計算出每個節點的所有得分值,計算後面節點的時候要用到前面節點得分值都取(max)最大的,以保證最後計算到f(8)時是全域性的最大值,例如計算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)分別代表啥各位看圖去吧。

回到開始,假如用蠻力乙個乙個列出所有路徑,不累死也得列的頭暈,用動態規劃的思想可以把乙個大問題拆分到每一步的小問題,下一步的小問題只需要在之前的小問題上再進一步,動態規劃的思想就像是小問題站巨人肩膀上,然後大問題莫名其妙就解決了。剛說的是從開始到結束的順序解法,要是從8節點到1節點逆序解法怎麼解?

維特比演算法的逆序解法

發現沒,最後最大都是0.6=f(1)=c(1~3) +c(3~4) +c(4~6) +c(6~8),而且直接都是看出來了,再一次說明了最大的路徑就是這條路徑。說了這麼多,上**

sentence ="經常有意見分歧" n=len(sentence) route={} route[n] = (0, 0)#route[n]:最大路徑的值,(0,0):當前這個詞的末尾座標 dag= for idx in range(n - 1, -1, -1): route[idx]= max(((dict.get(sentence[idx:x + 1])or 0) + route[x + 1][0],x )for x in dag[idx]) # 列表推倒求最大概率對數路徑 # route[idx] = max([ (概率值,詞語末字位置) for x in dag[idx] ]) # 以idx:(概率最大值,詞語末字位置)鍵值對形式儲存在route中) # route[x+1][0] 表示 詞路徑[x+1,n-1]的最大概率值, # [x+1][0]即表示取句子x+1位置對應元組(概率對數,詞語末字位置)的概率對數 print(route) #輸出結果:

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

上面只是一些核心的思路,好多地方可以繼續優化的,比如把概率值轉換成-log(概率值),目的是為了防止下溢問題,只是我舉例的概率值比較大,如果是乙個超大的dict,為了保證所有詞的概率之和約等於1,那每個詞對應的概率值會特別小。

(3)中文分詞以後得攻克的難點

1、分詞的規範,詞的定義還不明確,沒有乙個公認的、權威的標準。

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

3、未登入的新詞。就是咱們的dict裡沒有的詞,對於3這個比2對分詞的影響大多了,目前結巴分詞對此採取的方法是:基於漢字成詞能力的hmm模型,使用維特比演算法。

卷積碼的編譯碼原理與MATLAB實現

qquad 卷積碼又稱為連環碼,它和分組碼有明顯的區別。n,k 線性分組碼中,本組r n k個監督元僅與本組k個資訊元有關,與其他各組無關,即分組碼編碼器本身是無記憶性的。卷積碼則不同,每乙個 n,k 碼段 也稱為子碼,通常較短 內的n個碼元不僅與該段內資訊元有關,而且與前面的m段資訊元也相關。通常...

C 實現Huffman編碼和解碼

using system using system.collections using system.collections.generic using system.linq using system.text namespace stringcompresser public huffman c...

資料結構之赫夫曼編碼和解碼(C實現)

資料結構之赫夫曼編碼和解碼 c實現 編譯器 dev c 5.11 執行環境 win10 64bit by wain at stu include include include typedef struct htnode,huffmantree 動態分配陣列儲存哈夫曼樹 typedef char h...