jieba分詞原理

2021-09-13 00:17:42 字數 4696 閱讀 9914

關於jieba分詞的原理,在平時做文字方面的演算法時沒有仔細研究過,昨晚在網上看了一篇部落格,寫的很全面很詳細,其中有些深入的部分還並沒有完全看懂。

jieba分詞系統介紹:

涉及演算法:

基於字首詞典實現詞圖掃瞄,生成句子中漢字所有可能成詞情況所構成的有向無環圖(dag),採用動態規劃查詢最大概率路徑,找出基於詞頻的最大切分組合;

對於未登入詞,採用了基於漢字成詞能力的 hmm模型,採用viterbi演算法進行計算;

基於viterbi演算法的詞性標註;

jieba分詞系統,主要實現三個模組

分詞詞性標註

其中,分詞有三種模式,預設是精確模式

結巴分詞——基於字首詞典及動態規劃實現分詞

jieba分詞主要是基於統計詞典,構造乙個字首詞典;然後利用字首詞典對輸入句子進行切分,得到所有的切分可能,根據切分位置,構造乙個有向無環圖;通過動態規劃演算法,計算得到最大概率路徑,也就得到了最終的切分形式。

1.構建字首詞典:

基於統計詞典構造字首詞典,統計詞典有三列,第一列是詞,第二列是詞頻,第三列是詞性

2.構建有向無環圖:

根據字首詞典對輸入文字進行切分,比如「北」,有北、北京、北京大學三種劃分方式。因此,對於每個字,可以構建乙個以位置為key,相應劃分的末尾位置構成的列表為value的對映。

3.最大概率路徑計算

在得到所有可能的切分方式構成的有向無環圖後,我們發現從起點到終點存在多條路徑,多條路徑也就意味著存在多種分詞結果。需要計算最大概率路徑。

計算最大概率路徑時,jieba採用從後往前的方式,採用動態規劃計算最大概率路徑。每到達乙個節點,它前面的節點到終點的最大路徑概率就已經計算出來。

具體實現:

1.為什麼jieba沒有使用trie樹作為字首詞典儲存的資料結構

對於get_dag()函式來說,用trie資料結構,特別是在python環境,記憶體使用量過大。經實驗,可構造乙個字首集合解決問題。該集合儲存詞語及其字首,如set(['數', '資料', '資料結', '資料結構'])。在句子中按字正向查詢詞語,在字首列表中就繼續查詢,直到不在字首列表中或超出句子範圍。大約比原詞庫增加40%詞條。

2.最大概率路徑計算

jieba中計算最大概率路徑的主函式是calc(self,sentence,dag,route)

函式是乙個自底向上的動態規劃問題,它從sentence的最後乙個字(n-1)開始倒序遍歷sentence的每個字(idx)的方式,計算子句sentence[idx ~ n-1]的概率對數得分。然後將概率對數得分最高的情況以(概率對數,詞語最後乙個位置)這樣的元組儲存在route中。

基於漢字成詞能力的hmm模型識別未登入詞:

如果沒有字首詞典或者有些詞不在字首詞典中,jieba分詞一樣可以分詞,那麼jieba分詞是如何對未登入詞進行分詞呢?這就是本文將要講解的,基於漢字成詞能力的hmm模型識別未登入詞。

利用hmm模型進行分詞,主要是將分詞問題視為乙個序列標註(sequence labeling)問題,其中,句子為觀測序列,分詞結果為狀態序列。首先通過語料訓練出hmm相關的模型,然後利用viterbi演算法進行求解,最終得到最優的狀態序列,然後再根據狀態序列,輸出分詞結果。

1.序列標註

序列標註,就是將輸入句子和分詞結果當作兩個序列,句子為觀測序列,分詞結果為狀態序列,當完成狀態序列的標註,也就得到了分詞結果。

以「去北京大學玩」為例,我們知道「去北京大學玩」的分詞結果是「去 / 北京大學 / 玩」。對於分詞狀態,由於jieba分詞中使用的是4-tag,因此我們以4-tag進行計算。4-tag,也就是每個字處在詞語中的4種可能狀態,b、m、e、s,分別表示begin(這個字處於詞的開始位置)、middle(這個字處於詞的中間位置)、end(這個字處於詞的結束位置)、single(這個字是單字成詞)。具體如下圖所示,「去」和「玩」都是單字成詞,因此狀態就是s,「北京大學」是多字組合成的詞,因此「北」、「京」、「大」、「學」分別位於「北京大學」中的b、m、m、e。

2.hmm模型

hmm模型作的兩個基本假設:

p(states[t] | states[t-1],observed[t-1],...,states[1],observed[1]) = p(states[t] | states[t-1]) t = 1,2,...,t

p(observed[t] | states[t],observed[t],...,states[1],observed[1]) = p(observed[t] | states[t]) t = 1,2,...,t

hmm模型有三個基本問題:

其中,jieba分詞主要中主要涉及第三個問題,也即**問題。

hmm模型中的五元組表示:

3.維特比演算法

viterbi演算法實際上是用動態規劃求解hmm模型**問題,即用動態規劃求概率路徑最大(最優路徑)。這時候,一條路徑對應著乙個狀態序列。

根據動態規劃原理,最優路徑具有這樣的特性:如果最優路徑在時刻t通過結點 i∗t ,那麼這一路徑從結點 i∗t 到終點 i∗t 的部分路徑,對於從 i∗t 到 i∗t 的所有可能的部分路徑來說,必須是最優的。因為假如不是這樣,那麼從 i∗t 到 i∗t 就有另一條更好的部分路徑存在,如果把它和從 i∗t 到達 i∗t 的部分路徑連線起來,就會形成一條比原來的路徑更優的路徑,這是矛盾的。依據這個原理,我們只需要從時刻t=1開始,遞推地計算在時刻t狀態i的各條部分路徑的最大概率,直至得到時刻t=t狀態為i的各條路徑的最大概率。時刻t=t的最大概率就是最優路徑的概率 p∗ ,最優路徑的終結點 i∗t 也同時得到。之後,為了找出最優路徑的各個結點,從終結點 i∗t 開始,由後向前逐步求得結點 i∗t−1,...,i∗1 ,最終得到最優路徑 i∗=(i∗1,i∗2,...,i∗t) 。

由viterbi演算法得到狀態序列,也就可以根據狀態序列得到分詞結果。其中狀態以b開頭,離它最近的以e結尾的乙個子狀態序列或者單獨為s的子狀態序列,就是乙個分詞。以」去北京大學玩「的隱藏狀態序列」sbmmes「為例,則分詞為」s / bmme / s「,對應觀測序列,也就是」去 / 北京大學 / 玩」。

具體實現

jieba分詞中hmm模型識別未登入詞的原始碼目錄在jieba/finalseg/下,

__init__.py 實現了hmm模型識別未登入詞;

prob_start.py 儲存了已經訓練好的hmm模型的狀態初始概率表;

prob_trans.py 儲存了已經訓練好的hmm模型的狀態轉移概率表;

prob_emit.py 儲存了已經訓練好的hmm模型的狀態發射概率表;

jieba分詞會首先呼叫函式cut(sentence),cut函式會先將輸入句子進行解碼,然後呼叫__cut函式進行處理。__cut函式就是jieba分詞中實現hmm模型分詞的主函式。__cut函式會首先呼叫viterbi演算法,求出輸入句子的隱藏狀態,然後基於隱藏狀態進行分詞。

jieba分詞實現viterbi演算法是在viterbi(obs, states, start_p, trans_p, emit_p)函式中實現。viterbi函式會先計算各個初始狀態的對數概率值,然後遞推計算,每時刻某狀態的對數概率值取決於上一時刻的對數概率值、上一時刻的狀態到這一時刻的狀態的轉移概率、這一時刻狀態轉移到當前的字的發射概率三部分組成。

jieba的詞性標註

jieba分詞的詞性標註過程非常類似於jieba分詞的分詞流程,同時進行分詞和詞性標註。

在詞性標註的時候,首先基於正規表示式(漢字)進行判斷,

1)如果是漢字,則會基於字首詞典構建有向無環圖,然後基於有向圖計算最大概率路徑,同時在字首詞典中查詢所分出的詞的詞性,如果沒有找到,則將其詞性標註為「x」(非語素字 非語素字只是乙個符號,字母x通常用於代表未知數、符號);如果hmm標誌位置位,並且該詞為未登入詞,則通過隱馬爾科夫模型對其進行詞性標註;

2)如果是其它,則根據正規表示式判斷其型別,分別賦予「x」,「m」(數詞 取英語numeral的第3個字母,n,u已有他用),「eng」(英文)。

具體實現:

jieba分詞的詞性標註功能,是在jieba/posseg目錄下實現的。

其中,__init__.py實現了詞性標註的大部分函式;

char_state_tab.py儲存了離線統計的字及其對應的狀態;

prob_emit.py儲存了狀態到字的發射概率的對數值;

prob_start.py儲存了初始狀態的概率的對數值;

prob_trans.py儲存了前一時刻的狀態到當前時刻的狀態的轉移概率的對數值;

viterbi.py實現了viterbi演算法;

jieba分詞的詞性標註介面的主調函式是cut函式,位於jieba/posseg/__init__.py檔案中。

__cut_dag函式會首先根據離線統計的詞典(每行分別為字、頻率、詞性)構建字首詞典這個詞典。然後基於字首詞典構建有向無環圖,然後基於有向無環圖計算最大概率路徑,對句子進行分割。基於分割結果,如果該詞在詞--詞性詞典中,則將詞典中該詞的詞性賦予給這個詞,否則賦予「x」;如果字首詞典中不存在該詞,則這個詞是未登入詞,則利用隱馬爾科夫模型對其進行詞性標註;如果上述兩個條件都沒有滿足,則將詞性標註為「x」。

__cut_detail函式是利用隱馬爾科夫模型進行詞性標註的主函式。

__cut_detail函式首先利用正規表示式對未登入詞組成的句子進行分割,然後根據正規表示式進行判斷,如果匹配上,則利用隱馬爾科夫模型對其進行詞性標註;否則,進一步根據正規表示式,判斷其型別。

其中,__cut是隱馬爾科夫模型進行詞性標註的執行函式。

from jieba import analyse

tfidf = analyse.extract_tags #呼叫tfidf

textrank = analyse.textrank #呼叫textrank

jieba 利用jieba分詞

目錄 三種分詞模式 新增自定義詞典進行分詞 jieba提供了三種分詞模式,分別是全模式,精確模式和搜尋引擎模式。全模式下會將所有可能的詞語都進行分詞,精確模式下會盡可能的將句子精確切開,搜尋引擎模式實在精確模式的基礎上,對長詞再進行劃分,提高分詞的召回率。使用cut和cut for search即可...

Jieba分詞簡介

jieba分詞官網 jieba提供了三種分詞模式 精確模式,試圖將句子最精確地切開,適合文字分析 全模式,把句子中所有的可以成詞的詞語都掃瞄出來,速度非常快,但是不能解決歧義 搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。import jieba sent 用刀...

jieba分詞詞性

jieba詞性類別如下 ag形語素 形容詞性語素。形容詞 為 a,語素 前面置以a。a形容詞 取英語形容詞 adjective的第1個字母。ad副形詞 直接作狀語的形容詞。形容詞 a和副詞 d並在一起。an名形詞 具有名詞功能的形容詞。形容詞 a和名詞 n並在一起。b區別詞 取漢字 別 的聲母。c連...