1. 程式人生 > >中文分詞工具探析(二):Jieba

中文分詞工具探析(二):Jieba

【開源中文分詞工具探析】系列:

1. 前言

Jieba是由fxsjy大神開源的一款中文分詞工具,一款屬於工業界的分詞工具——模型易用簡單、程式碼清晰可讀,推薦有志學習NLP或Python的讀一下原始碼。與採用分詞模型Bigram + HMM 的ICTCLAS 相類似,Jieba採用的是Unigram + HMM。Unigram假設每個詞相互獨立,則分詞組合的聯合概率:

\begin{equation}
P(c_1^n) = P(w_1^m) = \prod_i P(w_{i})
\label{eq:unigram}
\end{equation}

在Unigram分詞後用HMM做未登入詞識別,以修正分詞結果。

2. 分解

以下原始碼分析基於jieba-0.36版本。

分詞模式

Jieba支援的三種分詞模式:全模式、精確模式、搜尋引擎模式。分詞函式jieba.cut()中有兩個模式調節引數cut_allHMM,分別表示是否採用全模式(若否,則為精確模式)、是否使用HMM。這兩個引數的組合對應於如下分詞模式:

  • cut_all=True, HMM=_對應於全模式,即所有在詞典中出現的詞都會被切分出來,實現函式為__cut_all
  • cut_all=False, HMM=False對應於精確模式且不使用HMM;按Unigram語法模型找出聯合概率最大的分詞組合,實現函式為__cut_DAG
  • cut_all=False, HMM=True
    對應於精確模式且使用HMM;在聯合概率最大的分詞組合的基礎上,HMM識別未登入詞,實現函式為__cut_DAG_NO_HMM

另一個分詞函式jieba.cut_for_search()對應於搜尋引擎模式,對長詞進行更細粒度的切分:

def cut_for_search(sentence, HMM=True):
    """
    Finer segmentation for search engines.
    """
    words = cut(sentence, HMM=HMM)
    for w in words:
        if len(w) > 2:
            for i in xrange(len(w) - 1):
                gram2 = w[i:i + 2]
                if FREQ.get(gram2):
                    yield gram2
        if len(w) > 3:
            for i in xrange(len(w) - 2):
                gram3 = w[i:i + 3]
                if FREQ.get(gram3):
                    yield gram3
        yield w

從上面的程式碼中,可以看出:對於長度大於2的詞,依次迴圈滾動取出在字首詞典中的二元子詞;對於長度大於3的詞,依次迴圈滾動取出在字首詞典中的三元子詞。至於字首詞典是什麼,且看下一小節。

詞典檢索

為了檢索詞典中的詞時,一般採取的思路是構建Trie樹——利用了字串的公共字首,以縮短查詢時間。作者當時也是這樣做的,用了兩個dict,trie dict用於儲存trie樹,lfreq dict用於儲存詞 -> 詞頻

def gen_trie(f_name):  
    lfreq = {}  
    trie = {}  
    ltotal = 0.0  
    with open(f_name, 'rb') as f:  
        lineno = 0   
        for line in f.read().rstrip().decode('utf-8').split('\n'):  
            lineno += 1  
            try:  
                word,freq,_ = line.split(' ')  
                freq = float(freq)  
                lfreq[word] = freq  
                ltotal+=freq  
                p = trie  
                for c in word:  
                    if c not in p:  
                        p[c] ={}  
                    p = p[c]  
                p['']='' #ending flag  
            except ValueError, e:  
                logger.debug('%s at line %s %s' % (f_name,  lineno, line))  
                raise ValueError, e  
    return trie, lfreq, ltotal

何不將字首資訊也放到lfreq中呢?Pull request 187中便有人提出來並實現了,還給lfreq取了個好聽的名字“字首字典”。

分詞DAG

一個句子所有的分詞組合構成了有向無環圖(Directed Acyclic Graph, DAG)\(G=(V,E)\),一個詞對應與DAG中的的一條邊\(e \in E\),邊的起點為詞的初始字元,邊的結點為詞的結束字元。jieba.get_DAG()函式實現切分句子得到DAG:

sentence = "印度報業托拉斯"
dag = jieba.get_DAG(sentence)
# {0: [0, 1, 6], 1: [1], 2: [2, 3], 3: [3], 4: [4, 5, 6], 5: [5, 6], 6: [6]}

DAG是用dict表示的,key為邊的起點,value為邊的終點集合,比如:上述例子中4 -> 6表示詞“托拉斯”。

求解Unigram模型

對於Unigram模型下的聯合概率\eqref{eq:unigram}求對數:

\[ \begin{aligned} \arg \max \prod_i P(w_i) & = \arg \max \log \prod_i P(w_i)\\ & = \arg \max \sum_i \log P(w_i) \end{aligned} \]

將詞頻的log值作為圖\(G\)邊的權值,從圖論的角度出發,將最大概率問題變成了最大路徑問題;是不是與ICTCLAS的處理思路有異曲同工之妙。在上面的DAG中,節點0表示源節點,節點m-1表示尾節點;則\(V=\{0, \cdots , m-1 \}\),且DAG滿足如下性質:

\[ v > u, \quad \forall \ (u,v) \in E \]

即DAG頂點的序號的順序與圖流向是一致的。Jieba用動態規劃(DP)來求解最大路徑問題,假設用\(d_i\)標記源節點到節點i的最大路徑的值,則有

\[ d_i = \max_{(j,i) \in E} \ \{ d_j+w(j,i) \} \]

其中,\(w(j,i)\)表示詞\(c_j^i\)的詞頻log值,\(w(i,i)\)表示字元\(c_i\)獨立成詞的詞頻log值。在求解上述式子時,需要知道所有節點i的前驅節點j;然後DAG中只有後繼結點list。在這裡,作者巧妙地用到了一個trick——從尾節點m-1往前推算的最優解等價於從源節點0往後推算的。那麼,用\(r_i\)標記節點i到尾節點的最大路徑的值,則

\[ r_i = \max_{(i,j) \in E} \ \{ r_j+w(i,j) \} \]

def calc(sentence, DAG, route):
    N = len(sentence)
    route[N] = (0, 0)
    logtotal = log(total)
    for idx in xrange(N - 1, -1, -1):
        # r[i] = max { log P(c_{i}^{x}) + r(x)}
        route[idx] = max((log(FREQ.get(sentence[idx:x + 1]) or 1) -
                          logtotal + route[x + 1][0], x) for x in DAG[idx])

關於HMM識別未登入詞,可看我之前寫的一篇《【中文分詞】隱馬爾可夫模型HMM》. 至此,Jieba完成了一個非常漂亮實用的分詞模型。

相關推薦

中文工具Jieba

【開源中文分詞工具探析】系列: 1. 前言 Jieba是由fxsjy大神開源的一款中文分詞工具,一款屬於工業界的分詞工具——模型易用簡單、程式碼清晰可讀,推薦有志學習NLP或Python的讀一下原始碼。與採用分詞模型Bigram + HMM 的ICTCLAS 相類似,Jieba採用的是Unigram +

開源中文工具Stanford CoreNLP

inf git deb seq 效果 analysis stream fix sps CoreNLP是由斯坦福大學開源的一套Java NLP工具,提供諸如:詞性標註(part-of-speech (POS) tagger)、命名實體識別(named entity recog

開源中文工具LTP

LTP是哈工大開源的一套中文語言處理系統,涵蓋了基本功能:分詞、詞性標註、命名實體識別、依存句法分析、語義角色標註、語義依存分析等。 【開源中文分詞工具探析】系列: 1. 前言 同THULAC一樣,LTP也是基於結構化感知器(Structured Perceptron, SP),以最大熵準則建模標註序列

開源中文工具THULAC

THULAC是一款相當不錯的中文分詞工具,準確率高、分詞速度蠻快的;並且在工程上做了很多優化,比如:用DAT儲存訓練特徵(壓縮訓練模型),加入了標點符號的特徵(提高分詞準確率)等。 【開源中文分詞工具探析】系列: 1. 前言 THULAC所採用的分詞模型為結構化感知器(Structured Percep

開源中文工具FNLP

FNLP是由Fudan NLP實驗室的邱錫鵬老師開源的一套Java寫就的中文NLP工具包,提供諸如分詞、詞性標註、文字分類、依存句法分析等功能。 【開源中文分詞工具探析】系列: 1. 前言 類似於THULAC,FNLP也是採用線性模型(linear model)分詞。較於對數線性模型(log-linea

開源中文工具Ansj

Ansj是由孫健(ansjsun)開源的一箇中文分詞器,為ICTLAS的Java版本,也採用了Bigram + HMM分詞模型(可參考我之前寫的文章):在Bigram分詞的基礎上,識別未登入詞,以提高分詞準確度。雖然基本分詞原理與ICTLAS的一樣,但是Ansj做了一些工程上的優化,比如:用DAT高效地實現檢

中文工具ICTCLAS (NLPIR)

【開源中文分詞工具探析】系列: 1. 前言 ICTCLAS是張華平老師推出的中文分詞系統,於2009年更名為NLPIR。ICTCLAS是中文分詞界元老級工具了,作者開放出了free版本的原始碼(1.0整理版本在此). 作者在論文[1] 中宣稱ICTCLAS是基於HHMM(Hierarchical Hid

Lucene 學習使用IK Analyzer中文

import java.io.IOException; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Fie

在PyCharmPython整合開發環境中安裝jieba中文工具

PyCharm IDE中,可以直接引入各種工具包。jieba中文分詞工具包安裝非常方便。 1、開啟Pycharm,點選左上角  >>File  >>Settings。 2、在settings介面中點選Project :***(專案名稱)  >

PyNLPIR python中文工具

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

北大開源全新中文工具準確率遠超THULAC、結巴

選自GitHub,作者:羅睿軒、許晶晶、孫栩,機器之心編輯。 最近,北大開源了一箇中文分詞工具包,它在多個分詞資料集上都有非常高的分詞準確率。其中廣泛使用的結巴分詞誤差率高達 18.55% 和 20.42,而北大的 pkuseg 只有 3.25% 與 4.32%。 pkuseg 是由北京

Spring AOPSpring AOP的實現機制

  Spring AOP 屬於第二代 AOP, 採用動態代理機制和位元組碼生成技術實現 。   與最初的 AspectJ 採用編譯器將橫切邏輯織入目標物件不同,動態代理機制和位元組碼生成都是在執行期間為目標物件生成一個代理物件,而將橫切邏輯織入到這個代理物件中

中文工具thulac4j釋出

1. 介紹 thulac4j是THULAC的Java 8工程化實現,具有分詞速度快、準、強的特點;支援 自定義詞典 繁體轉簡體 停用詞過濾 若想在專案中使用thulac4j,可新增依賴: <dependency> <groupId>io.github.yizhiru</g

乾貨 | 史上最全中文工具整理

作者 | fendouai 一.中文分詞  分詞服務介面列表 二.準確率評測: THULAC:與代表性分詞軟體的效能對比 我們選擇LTP-3.2.0 、ICTCLAS(2015版) 、jieba(C++版)等國內具代表性的分詞軟體與THULAC做效能

中文工具

THULAC 四款python中中文分詞的嘗試。嘗試的有:jieba、SnowNLP(MIT)、pynlpir(大資料搜尋挖掘實驗室(北京市海量語言資訊處理與雲端計算應用工程技術研究中心))、thulac(清華大學自然語言處理與社會人文計算實驗室) 四款都

python中文工具結巴jieba

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

jieba.NET是jieba中文的.NET版本C#實現

jieba.NET是jieba中文分詞的.NET版本(C#實現)。 當前版本為0.38.2,基於jieba 0.38,提供與jieba一致的功能與介面,以後可能會在jieba基礎上提供其它擴充套件功能。關於jieba的實現思路,可以看看這篇wiki裡提到的資料。 如果

Java中文工具AnsjSeg使用

        中文分詞是進行中文文字分析的一個重要步驟。對於Java語言,有許多可選的分詞工具,如中科院計算所的NLPIR(原ICTCLASS)、盤古分詞、IKAnalyzer、PaodingAnalyzer,其中,試用過ICTCLASS及其後續版本,剛開始感覺不錯,但是Java呼叫C語言的方式實在是受

搭建部署 布式ELK平臺

正在 .com ace 自己 images 連接 文件描述符 setting default logstash? logstash 是什麽 – logstash是一個數據采集、加工處理以及傳輸的工具? logstash 特點: – 所有類型的數據集中處理

豹哥嵌入式講堂ARM Cortex-M調試過程1- 4線接口標準JTAG

狀態機 alt 端口 含義 允許 ati state 數據 identity   大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是嵌入式調試裏的接口標準JTAG。   在結束《ARM Cortex-M開發文件詳解》系列文章之後,豹哥修整了一小段時間,但是講課的