1. 程式人生 > >中文分詞的基本原理以及jieba分詞的用法

中文分詞的基本原理以及jieba分詞的用法

結巴分詞是國內程式設計師用Python開發的一箇中文分詞模組,可能是最好的Python中文分片語件?

中文分詞的原理

1、中文分詞(Chinese Word Segmentation) 指的是將一個漢字序列切分成一個一個單獨的詞。分詞就是將連續的字序列按照一定的規範重新組合成詞序列的過程
2、現有的分詞演算法可分為三大類:基於字串匹配的分詞方法、基於理解的分詞方法和基於統計的分詞方法
基於字串匹配的分詞方法:這種方法又叫做機械分詞方法,它是按照一定的策略將待分析的漢字串與一個“充分大的”機器詞典中的詞條進行配,若在詞典中找到某個字串,則匹配成功(識別出一個詞)
1)正向最大匹配法(由左到右的方向)
2)逆向最大匹配法(由右到左的方向):
3)最少切分(使每一句中切出的詞數最小)
4)雙向最大匹配法(進行由左到右、由右到左兩次掃描)
基於理解的分詞方法:這種分詞方法是通過讓計算機模擬人對句子的理解,達到識別詞的效果。其基本思想就是在分詞的同時進行句法、語義分析,利用句法資訊和語義資訊來處理歧義現象。它通常包括三個部分:分詞子系統、句法語義子系統、總控部分。在總控部分的協調下,分詞子系統可以獲得有關詞、句子等的句法和語義資訊來對分詞歧義進行判斷,即它模擬了人對句子的理解過程。這種分詞方法需要使用大量的語言知識和資訊。由於漢語語言知識的籠統、複雜性,難以將各種語言資訊組織成機器可直接讀取的形式,因此目前基於理解的分詞系統還處在試驗階段。
基於統計的分詞方法:給出大量已經分詞的文字,利用統計機器學習模型學習詞語切分的規律(稱為訓練),從而實現對未知文字的切分。例如最大概率分詞方法和最大熵分詞方法等。隨著大規模語料庫的建立,統計機器學習方法的研究和發展,基於統計的中文分詞方法漸漸成為了主流方法。
主要統計模型:N元文法模型(N-gram),隱馬爾可夫模型(Hidden Markov Model ,HMM),最大熵模型(ME),條件隨機場模型(Conditional Random Fields,CRF)等。

jieba分詞的

Feature

  • 支援三種分詞模式
    1 精確模式,試圖將句子最精確地切開,適合文字分析;

    2 全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;
    3 搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。
  • 支援繁體分詞
  • 支援自定義詞典

基本用法示例

1、分詞

# -*- coding: utf-8 -*-

import jieba
import jieba.posseg as pseg
import jieba.analyse

str1 = "我來到北京清華大學"
str2 = 'python的正則表示式是好用的'
str3 = "小明碩士畢業於中國科學院計算所,後在日本京都大學深造"

seg_list = jieba.cut(str1,cut_all = True)   ##全模式
result = pseg.cut(str1)                     ##詞性標註,標註句子分詞後每個詞的詞性
result2 = jieba.cut(str2)                   ##預設是精準模式
result3 =  jieba.analyse.extract_tags(str1,2)
##關鍵詞提取,引數setence對應str1為待提取的文字,topK對應2為返回幾個TF/IDF權重最大的關鍵詞,預設值為20
result4 = jieba.cut_for_search(str3)        ##搜尋引擎模式

print " /".join(seg_list)
>>>我 /來到 /北京 /清華 /清華大學 /華大 /大學

for w in  result:
    print w.word, "/", w.flag, ", ",
>>>我 / r ,  來到 / v ,  北京 / ns ,  清華大學 / nt ,  

for t in result2:
    print t,
>>>python 的 正則表示式 是 好 用 的

for s in result3:
    print s
>>>清華大學
    來到

print " ,".join(result4)
>>>小明 ,碩士 ,畢業 ,於 ,中國 ,科學 ,學院 ,科學院 ,中國科學院 ,計算 ,計算所 ,, ,後 ,在 ,日本 ,京都 ,大學 ,日本京都大學 ,深造

2、返回詞所在位置

import jieba

test_sent = u"永和服裝飾品有限公司"
result = jieba.tokenize(test_sent) ##Tokenize:返回詞語在原文的起始位置
for tk in result:
    print "word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2])
    print tk
>>>
>word 永和         start: 0        end:2
(u'\u6c38\u548c', 0, 2)
word 服裝      start: 2        end:4
(u'\u670d\u88c5', 2, 4)
word 飾品      start: 4        end:6
(u'\u9970\u54c1', 4, 6)
word 有限公司        start: 6        end:10
(u'\u6709\u9650\u516c\u53f8', 6, 10)

3、自定義詞典

# -*- coding: utf-8 -*-
import sys
import jieba
jieba.load_userdict('userdict.txt')

test_sent = "大連美容美髮學校中君意是你值得信賴的選擇"
test_sent2 = '江州市長江大橋參加了長江大橋的通車儀式'

print ", ".join(jieba.cut(test_sent))
>>>大連, 美容美髮, 學校, 中, 君意, 是, 你, 值得, 信賴, 的, 選擇

print ", ".join(jieba.cut(test_sent2))
>>>江州, 市長, 江大橋, 參加, 了, 長江大橋, 的, 通車, 儀式

"""
自定義詞典的格式:一個詞佔一行;每一行分三部分,一部分為詞語,另一部分為詞頻,最後為詞性(可省略),用空格隔開
其中user_dict.txt的內容是:
雲端計算 5
李小福 2 nr
創新辦 3 i
easy_install 3 eng
好用 300
韓玉賞鑑 3 nz
八一雙鹿 3 nz
臺中
凱特琳 nz
Edu Trust認證 2000
君意 3
江大橋 20000
"""

jieba分詞的基本原理

第一條:基於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, 效果也差不到哪裡去.

參考文獻