1. 程式人生 > >對Python中文分詞模組結巴分詞演算法過程的理解和分析

對Python中文分詞模組結巴分詞演算法過程的理解和分析

結巴分詞是國內程式設計師用python開發的一箇中文分詞模組, 原始碼已託管在github, 地址在: https://github.com/fxsjy/jieba

作者的文件寫的不是很全, 只寫了怎麼用, 有一些細節的文件沒有寫.

以下是作者說明檔案中提到的結巴分詞用到的演算法:

基於Trie樹結構實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖(DAG)
採用了動態規劃查詢最大概率路徑, 找出基於詞頻的最大切分組合
對於未登入詞,採用了基於漢字成詞能力的HMM模型,使用了Viterbi演算法
因為最近有點興趣想了解中文分詞, 所以看了大量的資料, 對上面的三條有了一點點理解, 不再是兩眼一抹黑了.轉載請註明: 本文來自Django夢之隊, http://ddtcms.com/blog/archive/2013/2/4/69/jieba-fenci-suanfa-lijie/

先推薦大家看 http://www.52nlp.cn/ (我愛自然語言處理)的一系列關於概率、中文分詞、HMM隱馬爾科夫模型的文章, 然後再回頭看看結巴分詞的程式碼。

然後推薦大家看看《解密搜尋引擎技術實戰:Lucene&Java精華版》,如果看不到, 可以看看這裡的線上版, 雖然很短, 但是基本的思想都說明白了, 地址: http://book.51cto.com/art/201106/269050.htm (4.6 概率語言模型的分詞方法)

看了這本書的第4章, 或者看了那個線上的那個章節的前後部分, 基本上可以說, 結巴分詞, 在很大的程度上類似於書中說的例子。(上面的連結,是作者演算法的第2條, 動態規劃查詢最大概率路徑),當然, 結巴分詞使用了HMM模型對未登入詞進行識別(上面的第3條)

至於第1條, 作者的trie樹,可以看這篇文章對python中如何儲存trie樹結構的詞典進行深刻理解:http://iregex.org/blog/trie-in-python.html Trie in Python 這篇寫的很好, 主要分析 Trie 實現原理,並給出 Python 的實現,還和正則聯絡到一起了。

上面列出的三個連結, 裡面講到的知識, 基本上將結巴分詞的演算法都講到了。所以有興趣的人, 一定要仔細看我上面給的三個連結。

下面, 結合自己看結巴分詞的程式碼, 講講我自己看過資料和程式碼後的理解。

先從作者的三條說起。

第一條:基於Trie樹結構實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖(DAG)

這個看上面的trie樹的python實現, 結巴分詞自帶了一個叫做dict.txt的詞典, 裡面有2萬多條詞, 包含了詞條出現的次數(這個次數是於作者自己基於人民日報語料等資源訓練得出來的)和詞性. 這個第一條的trie樹結構的詞圖掃描, 說的就是把這2萬多條詞語, 放到一個trie樹中, 而trie樹是有名的字首樹, 也就是說一個詞語的前面幾個字一樣, 就表示他們具有相同的字首, 就可以使用trie樹來儲存, 具有查詢速度快的優勢.

聰明的人可能會想到把 dict.txt中所有的詞彙全部刪掉, 然後再試試結巴能不能分詞, 結果會發現, 結巴依然能夠分詞, 不過分出來的詞, 大部分的長度為2.這個就是第三條, 基於HMM來預測分詞了.

接著說DAG有向無環圖, 就是後一句的 生成句子中漢字所有可能成詞情況所構成的有向無環圖, 這個是說的, 給定一個句子, 要你分詞, 也就是給定一個 待分詞的句子, 對這個句子進行生成有向無環圖. 如果對有向無環圖理解不了可以百度或者google搜尋, 也可以看這篇 http://book.51cto.com/art/201106/269048.htm 比較形象的用圖來表示了一個待分詞句子的切分情況.

作者是怎麼切分的呢? 1. 根據dict.txt生成trie樹, 2, 對待分詞句子, 根據dict.txt生成的trie樹, 生成DAG, 實際上通俗的說, 就是對待分詞句子, 根據給定的詞典進行查詞典操作, 生成幾種可能的句子切分. dag是啥玩意?記錄了啥呢? 作者的原始碼中記錄的是句子中某個詞的開始位置, 從0到n-1(n為句子的長度), 每個開始位置作為字典的鍵, value是個list, 其中儲存了可能的詞語的結束位置(通過查字典得到詞, 開始位置+詞語的長度得到結束位置)

例如:{0:[1,2,3]} 這樣一個簡單的DAG, 就是表示0位置開始, 在1,2,3位置都是詞, 就是說0~1, 0~2,0~3這三個起始位置之間的字元, 在dict.txt中是詞語.

第二條:採用了動態規劃查詢最大概率路徑, 找出基於詞頻的最大切分組合

關於動態規劃查詢最大概率路徑, 這個在一些大學課程中講的很多了, 不熟悉的或者忘記了的翻翻百度就行了. 上面給的那個線上書籍的連結中也說的很明白了, 我這裡就說說作者的程式碼:

作者的程式碼中講字典在生成trie樹的同時, 也把每個詞的出現次數轉換為了頻率. 關於頻率和概率, 這裡在囉嗦幾句: 按照定義, 頻率其實也是一個0~1之間的小數, 是 事件出現的次數/實驗中的總次數, 因此在試驗次數足夠大的情況下, 頻率約等於概率, 或者說頻率的極限就是概率. 不過通常人們混淆的是頻率和次數, 經常把頻率等同於事件出現的次數, 比如這裡就是某個詞語出現的次數, 所以, 頻率在引起混淆的時候, 對中國人來說, 還是先理解為出現次數, 然後理解發現有問題, 就理解為出現次數/總數這個比率吧.

動態規劃中, 先查詢待分詞句子中已經切分好的詞語, 對該詞語查詢該詞語出現的頻率(次數/總數), 如果沒有該詞(既然是基於詞典查詢, 應該是有的), 就把詞典中出現頻率最小的那個詞語的頻率作為該詞的頻率, 也就是說P(某詞語)=FREQ.get(‘某詞語’,min_freq), 然後根據動態規劃查詢最大概率路徑的方法, 對句子從右往左反向計算最大概率(一些教科書上可能是從左往右, 這裡反向是因為漢語句子的重心經常落在後面, 就是落在右邊, 因為通常情況下形容詞太多, 後面的才是主幹, 因此, 從右往左計算, 正確率要高於從左往右計算, 這個類似於逆向最大匹配), P(NodeN)=1.0, P(NodeN-1)=P(NodeN)*Max(P(倒數第一個詞))…依次類推, 最後得到最大概率路徑, 得到最大概率的切分組合.

第三條, 對於未登入詞,採用了基於漢字成詞能力的HMM模型,使用了Viterbi演算法

未登入詞, 作者說的是什麼意思? 其實就是詞典 dict.txt 中沒有記錄的詞. 上面說了, 把dict.txt中的所有詞語都刪除了, 結巴分詞一樣可以分詞, 就是說的這個.

怎麼做到的? 這個就基於作者採用的HMM模型了, 中文詞彙按照BEMS四個狀態來標記, B是開始begin位置, E是end, 是結束位置, M是middle, 是中間位置, S是singgle, 單獨成詞的位置, 沒有前, 也沒有後. 也就是說, 他採用了狀態為(B,E,M,S)這四種狀態來標記中文詞語, 比如北京可以標註為 BE, 即 北/B 京/E, 表示北是開始位置, 京是結束位置, 中華民族可以標註為BMME, 就是開始, 中間, 中間, 結束.

經過作者對大量語料的訓練, 得到了finalseg目錄下的三個檔案(來自結巴專案的issues):

要統計的主要有三個概率表:

prob_trans.py
1)位置轉換概率,即B(開頭),M(中間),E(結尾),S(獨立成詞)四種狀態的轉移概率;
{‘B’: {‘E’: 0.8518218565181658, ‘M’: 0.14817814348183422},
‘E’: {‘B’: 0.5544853051164425, ‘S’: 0.44551469488355755},
‘M’: {‘E’: 0.7164487459986911, ‘M’: 0.2835512540013088},
‘S’: {‘B’: 0.48617017333894563, ‘S’: 0.5138298266610544}}

P(E|B) = 0.851, P(M|B) = 0.149,說明當我們處於一個詞的開頭時,下一個字是結尾的概率
要遠高於下一個字是中間字的概率,符合我們的直覺,因為二個字的詞比多個字的詞更常見。

prob_emit.py
2)位置到單字的發射概率,比如P(“和”|M)表示一個詞的中間出現”和”這個字的概率;
prob_start.py
3) 詞語以某種狀態開頭的概率,其實只有兩種,要麼是B,要麼是S。這個就是起始向量, 就是HMM系統的最初模型狀態
實際上, BEMS之間的轉換有點類似於2元模型, 就是2個詞之間的轉移
二元模型考慮一個單詞後出現另外一個單詞的概率,是N元模型中的一種。
例如:一般來說,”中國”之後出現”北京”的概率大於”中國”之後出現”北海”的概率,也就是:中國北京 比 中國北海出現的概率大些, 更有可能是一箇中文詞語.

不過, 作者這裡應該不是用的2元分詞模型的, 這裡的BEMS只提供了單個漢字之間的轉換, 發射概率, 並沒有提供粒度更大的, 基於詞語的發射和轉移概率, 當然, 也有可能我理解的不夠深入.

給定一個 待分詞的句子, 就是觀察序列, 對HMM(BEMS)四種狀態的模型來說, 就是為了找到一個最佳的BEMS序列, 這個就需要使用viterbi演算法來得到這個最佳的隱藏狀態序列, 具體的python版的viterbi演算法請看維基百科:http://zh.wikipedia.org/wiki/%E7%BB%B4%E7%89%B9%E6%AF%94%E7%AE%97%E6%B3%95 維特比演算法

通過作者之前訓練得到的概率表和viterbi演算法, 就可以得到一個概率最大的BEMS序列, 按照B打頭, E結尾的方式, 對待分詞的句子重新組合, 就得到了分詞結果. 比如 對待分詞的句子 ‘全世界都在學中國話’ 得到一個BEMS序列 [S,B,E,S,S,S,B,E,S] 這個序列只是舉例, 不一定正確, 通過把連續的BE湊合到一起得到一個詞, 單獨的S放單, 就得到一個分詞結果了: 上面的BE位置和句子中單個漢字的位置一一對應, 得到全/S 世界/BE 都/S 在/S 學/S 中國/BE 話/S 從而將句子切分為詞語.

以上, 就是作者這三條介紹的全部理解和分析, 對於其中任何術語不理解, 請使用搜索引擎.

結巴分詞的過程:

1. 載入字典, 生成trie樹

2. 給定待分詞的句子, 使用正則獲取連續的 中文字元和英文字元, 切分成 短語列表, 對每個短語使用DAG(查字典)和動態規劃, 得到最大概率路徑, 對DAG中那些沒有在字典中查到的字, 組合成一個新的片段短語, 使用HMM模型進行分詞, 也就是作者說的識別新詞, 即識別字典外的新詞.

3. 使用python的yield 語法生成一個詞語生成器, 逐詞語返回. 當然, 我認為直接返回list, 效果也差不到哪裡去.

另外談談結巴分詞的不足和侷限:

1 在中文分詞的時候, 字典起到的作用貌似不大, 因為基於單字的HMM(BEMS)模型貌似就可以分詞了, 不管正確率如何, 總算能分了.字典起到的作用在後面說.說作用不大, 是因為沒有字典也能分詞. 另外, 生成了DAG之後, 又用動態規劃, 覺得浪費步驟.小概率連乘下限可能溢位已修正, 就不多說了.

2. 中文分詞載入dict.txt這個字典後, 佔用的記憶體為140多M, 覺得佔用記憶體過多. 專業化的詞典生成, 還不方便. 怎麼訓練自己的專用概率表, 就沒有提供工具, 如果提供了訓練自己的HMM模型工具, 估計更好.

3. 沒有那個字典的話, Trie和DAG都不起作用, 僅靠HMM模型的viterbi演算法起作用, 因此看出詞典的作用就是用來矯正HMM模型的分詞結果, 但是HMM分詞的結果生成方式是把B開始E結束的序列, 組合成一個詞, 因此, 這種判斷方法不一定正確, 比如BES能不能算作一個詞的序列我覺得值得考慮.

4. HMM是不是真的能夠識別新詞呢? 我認為是肯定的, 但是是要打折扣的. 這個跟作者訓練的詞庫有關係, 新詞的字出現的概率在一段時間內會井噴, 但在長期的語言現象中, 應該還是平穩的, 除非這個詞從一出現就很流行, 而且會流行很長的時間.因此HMM識別新詞的功能在時效性上是不足的, 他只能識別2個字的詞, 對於3個字的新詞, 估計就能力有限了. 這個有待於BEMS序列組合成詞的演算法的改變和新詞獲取演算法的改變, 才能得到改善.

5. 引入二元分詞的判斷, 可能對詞典的依賴會降低一點, 現在的詞典的使用就是為了彌補HMM在識別多字詞方面能力欠佳的問題, 所以詞典中儲存的是3 ,4 個字的詞語.

6. 詞性標註的問題, 在分詞的時候, 不能同時識別詞性, 因為分詞的時候沒有處理詞性, 也就是說分詞的時候, 沒有語義分析的.詞性標註的部分, 是使用另外的posseg模組進行的.還有一個問題是新詞的詞性可能沒法識別, 同樣這個是說那些3, 4字詞.

7. 對專有名詞比如人名 地名 機構名 的識別, 不能說好.

8. 文件太少了, 關於詞性標註, 得到的結果沒有一點分析, 詞性來源於哪裡都沒有說明. 不利於大家一起改進.句法分析, 語義分析都是沒有的.

9. 詞性標註應該也是基於BEMS標註進行的. 不知道是不是可以獨立出來.就是說基於語義來標示詞性或者基於詞語在句子中的位置來做推斷進行標註詞性.

10. 分詞過程中, 不能獲得這個句子中出現的詞的次數資訊, 或者說出現頻率高的詞, 不能用於抽取文章的關鍵詞.

第12次修改, 全文完, 歡迎拍磚.轉載請註明來自Django夢之隊, http://ddtcms.com/blog/archive/2013/2/4/69/jieba-fenci-suanfa-lijie/

相關推薦

Python中文模組結巴演算法過程理解分析

結巴分詞是國內程式設計師用python開發的一箇中文分詞模組, 原始碼已託管在github, 地址在: https://github.com/fxsjy/jieba 作者的文件寫的不是很全, 只寫了怎麼用, 有一些細節的文件沒有寫. 以下是作者說明檔案中提到的結巴分

學習筆記--中文結巴(二)

結巴中文分詞簡介    1)支援三種分詞模式: 精確模式:將句子最精確的分開,適合文字分析 全模式:句子中所有可以成詞的詞語都掃描出來,速度快,不能解決歧義 搜尋引擎模式:在精確的基礎上,對長詞再次切分,提高召回    2)支援繁體分詞    3)支援自定義詞典

解決js中模組頁列表,怎麼做

最近工作中在做一個分頁列表的一個東西,要求在js中寫,不多比比,直接上關鍵程式碼 htmlText=htmlText+'<div class="page">'; //重寫分頁列表 //一頁的內容 var pageSize = parse

Python解釋器種類以及特點 (經典概括, 便於理解記憶)

span 開發 python解釋器 技術 c語言開發 目標 提高 python代碼 child CPython c語言開發的 使用最廣的解釋器 IPython 基於cpython之上的一個交互式計時器 交互方式增強 功能和cpython一樣 PyPy 目標是

梯度下降演算法理解實現

# 對梯度下降演算法的理解和實現 ​ 梯度下降演算法是機器學習程式中非常常見的一種引數搜尋演算法。其他常用的引數搜尋方法還有:牛頓法、座標上升法等。 ## 以線性迴歸為背景 ​ 當我們給定一組資料集合 $D=\{(\mathbf{x^{(0)}},y^{(0)}),(\mathbf{x^{(1)}},y

python中文,使用結巴python進行

php 分詞 在采集美女站時,需要對關鍵詞進行分詞,最終采用的是python的結巴分詞方法.中文分詞是中文文本處理的一個基礎性工作,結巴分詞利用進行中文分詞。其基本實現原理有三點:基於Trie樹結構實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖(DAG)采用了動態規劃查找最大概率

Python第三方庫jieba(結巴-中文)入門與進階(官方文檔)

修改 demo 特點 pypi nlp CA 動態修改 tag 官方文檔 jieba “結巴”中文分詞:做最好的 Python 中文分詞組件。下載地址:https://github.com/fxsjy/jieba 特點 支持三種分詞模式: 精確模式,試圖將句子最精確地

使用結巴(jieba)自然語言進行特徵預處理(Python、Java 實現)

一、前言 之前使用基於 Python 語言的 Spark 進行機器學習,程式設計起來是十分簡單。 ① 但是演算法部署到雲伺服器上,是一個障礙。 ② 得藉助 Flask/Django 等 Python W

python︱六款中文模組嘗試:jieba、THULAC、SnowNLP、pynlpir、CoreNLP、pyLTP

**公眾號“素質雲筆記”定期更新部落格內容:** ![這裡寫圖片描述](https://img-blog.csdn.net/20180226155348545?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lu

使用python中的結巴作詞雲圖,微信功能點進行輔助分析

工作室任務:基於知乎評論,分析微信功能點,做一次分享會。 一、原料和準備 1.從網上爬蟲的文件,儲存為txt文件,本例來源https://www.zhihu.com/question/23178234?from=groupmessage&isappinstalled

python中文工具:結巴jieba

結巴分詞jieba特點    支援三種分詞模式:        精確模式,試圖將句子最精確地切開,適合文字分析;        全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;        搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提

Python利用結巴進行中文

利用結巴分詞進行中文分詞,選擇全模式,建立詞倒排索引,並實現一般多詞查詢和短語查詢 # -*- coding: utf-8 -*- import jieba ''' Created on 2015-11-23 ''' def word_split(text): "

jieba(結巴)—— Python 中文

學術界著名的分詞器: 中科院的 ICTCLAS,程式碼並不十分好讀 哈工大的 ltp, 東北大學的 NIU Parser, 另外,中文 NLP 和英文 NLP 不太一致的地方還在於,中文首先需要分詞,針對中文的分詞問題,有兩種基本的解決思路: 啟發式(He

Python 結巴 關鍵詞抽取分析

等於 範圍 分類問題 urn post bre 依然 信息檢索 有意 關鍵詞抽取就是從文本裏面把跟這篇文檔意義最相關的一些詞抽取出來。這個可以追溯到文獻檢索初期,當時還不支持全文搜索的時候,關鍵詞就可以作為搜索這篇論文的詞語。因此,目前依然可以在論文中看到關鍵詞這一項。

PyNLPIR python中文工具

命名 hub 兩個 工具 ict mage ret wid tty 官網:https://pynlpir.readthedocs.io/en/latest/ github:https://github.com/tsroten/pynlpir NLPIR分詞系

Python結巴使用手記

img 3年 方法封裝 python token sys.path 裝飾 arp mage 結巴分詞方法封裝類 from __future__ import unicode_literals import sys sys.path.append("../")

python基礎===jieba模塊,Python 中文組件

word cut 用法 地址 api mas 精確 == com api參考地址:https://github.com/fxsjy/jieba/blob/master/README.md 安裝自行百度 基本用法: import jieba #全模式 word = jie

Python中文 jieba

問題 turn Coding windows 停用 分享圖片 詞典 ces text1 三種分詞模式與一個參數 以下代碼主要來自於jieba的github,你可以在github下載該源碼 import jieba seg_list = jieba.cut("我來到北京清

python 結巴(jieba)詳解

【轉自:https://www.cnblogs.com/jackchen-Net/p/8207009.html】 “結巴”中文分詞:做最好的 Python 中文分片語件 "Jieba" (Chinese for "to stutter") Chinese text segmentation:

python中文器(jieba類庫)

 先上效果圖: 資料來源: 分詞後的txt檔案: 分詞後的excel檔案: 原始碼: #!/usr/bin/python # -*- coding: UTF-8 -*- # *************************************