Jieba 中文分詞 -一- ——分詞與自定義字典

jieba 分詞特點

支持四種分詞模式:

jieba 分詞安裝

全自動安裝:

pip install jieba (window環境)
pip3 install jieba (Linux環境)

半自動安裝:

先下載 http://pypi.python.org/pypi/jieba/
解壓後運行 python setup.py install

手動安裝:

將 jieba 目錄放置於當前目錄或者 site-packages 目錄

通過 import jieba 來引用

如果需要使用 paddle 模式下的分詞和詞性標註功能,請先安裝 paddlepaddle-tiny,pip install paddlepaddle-tiny==1.6.1

主要功能

分詞

1、基本步驟

初始化


初始化時,先加載詞典文件 dict.txt,遍歷每一行,生成詞語 - 詞數的鍵值對和總詞數,並將生成結果保存到 cache 中,下次直接從 cache 中讀取即可。

初始化可以簡單理解爲,讀取詞典文件,構建詞語 - 詞數鍵值對,方便後面步驟中查詞典,也就是字符串匹配。

切分短語


  1. 首先進行將語句轉換爲 UTF-8 或者 GBK。

  2. 然後根據用戶指定的模式,是否全模式,是否採用 HMM 隱馬爾科夫,來設置 cut 方式。

  3. 然後根據正則,將輸入文本分爲一個個語句。

  4. 最後遍歷語句,對每個語句單獨進行分詞。

構建 DAG


看構建 DAG 的過程。

先遍歷一個個切分好的短語,對這些短語來進行分詞。

首先要構建短語的有向無環圖 DAG。查詞典進行字符串匹配的過程中,可能會出現好幾種可能的切分方式,將這些組合構成有向無環圖,如下圖所示:

得到語句的有向無環圖 DAG,DAG 中記錄了某個詞的開始位置和它可能的結束位置。開始位置作爲 key,結束位置是一個 list。

上面語句的完整 DAG 爲:

{0: [1, 2],    1: [2],    2: [3, 4, 5],    3: [4],    4: [5] }

比如位置 0 的 DAG 表達爲 {0: [1, 2]}, 也就是說 0 位置爲詞的開始位置時,1, 2 位置都有可能是詞的結束位置。

動態規劃構建 Route,計算從語句末尾到語句起始,DAG 中每個節點到語句結束位置的最大路徑概率,以及概率最大時節點對應詞語的結束位置。

def calc(self, sentence, DAG, route):
    N = len(sentence)
    route[N] = (0, 0)
    logtotal = log(self.total)
    for idx in xrange(N - 1, -1, -1):
# route[idx] = (該漢字到最後一個漢字的最大路徑概率, 
  # 最大路徑概率時該漢字對應的詞語結束位置).
# 遍歷DAG中該漢字節點的結束位置,也就是DAG[idx],
  # 計算idx到x之間構成的詞語的概率,然後乘以x到語句結束位置的最大概率,
  # 即可得到idx到語句結束的路徑最大概率.
        route[idx] = max(
                       (log(self.FREQ.get(sentence[idx:x + 1]) or 1) 
                        - log(total) 
                       + route[x + 1][0]
                     , x) for x in DAG[idx])
# 每個詞的概率 = 字典中該詞的詞數 / 字典總詞數。

對於上圖構建每個節點的最大路徑概率的過程如下:

p(5)= 1, p(4)= max(p(5) * p(4->5)),
p(3)= max(p(4) * p(3->4)),
p(2)= max(p(3) * p(2->3),   p(4) * p(2->4),   p(5) * p(2->5)),
對於節點 2,他有 2->3, 2->4, 2->4 三條路徑,我們取概率最大的路徑作爲節點 2 的路徑概率,並記下概率最大時節點 2 的結束位置。

p(1) = max(p(2) * p(1->2)) p(0) = max(p(1) * p(0->1),   p(2) * p(0->2))

遍歷每個節點的 Route,組裝詞語組合。

如果詞語不在字典中,也就是新詞,使用 HMM 隱馬爾科夫模型進行分割。

通過 yield 將詞語逐個返回。

2、基本方法

待分詞的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建議直接輸入 GBK 字符串,可能無法預料地錯誤解碼成 UTF-8。

jieba.cut(sentence, 
          cut_all=False, 
          HMM=True, 
          use_paddle=False)

sentence:  需要分詞的字符串
cut_all:  用來控制是否採用全模式
HMM: 用來控制是否使用 HMM 模型
use_paddle: 用來控制是否使用 paddle 模式下的分詞模式,paddle 模式採用延遲加載方式,通過 enable_paddle 接口

 jieba.cut_for_search(sentence, HMM=True)

該方法適合用於搜索引擎構建倒排索引的分詞,粒度比較細。

sentence: 分詞的字符串
HMM: 使用 HMM 模型

jieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可以使用 for 循環來獲得分詞後得到的每一個詞語 (unicode)

jieba.lcut 以及 jieba.lcut_for_search 直接返回 list

jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定義分詞器,可用於同時使用不同詞典。jieba.dt 爲默認分詞器,所有全局分詞相關函數都是該分詞器的映射。

代碼示例:

# encoding=utf-8
import jieba

jieba.enable_paddle()# 啓動paddle模式。
strs=["我關注了數據STUDIO","我是數據分析師","四川大學"]
for str in strs:
    seg_list = jieba.cut(str,use_paddle=True) # 使用paddle模式
    print("Paddle Mode: " + '/'.join(list(seg_list)))

seg_list = jieba.cut("我畢業於四川大學,我關注了數據STUDIO", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list))  # 全模式

seg_list = jieba.cut("我畢業於四川大學,我關注了數據STUDIO", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list))  # 精確模式

seg_list = jieba.cut("他來到了網易杭研大廈")  # 默認是精確模式
print(", ".join(seg_list))

seg_list = jieba.cut_for_search("我是雲朵君,我關注了數據STUDIO")  # 搜索引擎模式
print(", ".join(seg_list))

Paddle enabled successfully......
Paddle Mode: 我 / 關注 / 了 / 數據 / STUDIO
Paddle Mode: 我 / 是 / 數據 / 分析師
Paddle Mode: 四川大學
Full Mode: 我 / 畢業 / 於 / 四川 / 四川大學 / 大學 / ,/ 我 / 關注 / 了 / 數據 / STUDIO
Default Mode: 我 / 畢業 / 於 / 四川大學 / ,/ 我 / 關注 / 了 / 數據 / STUDIO
他, 來到, 了, 網易, 杭研, 大廈
我, 是, 雲朵, 君, ,, 我, 關注, 了, 數據, STUDIO

添加自定義詞典

1、原始詞典

詞典是基於字符串匹配的分詞算法的關鍵所在,決定了最終分詞的準確度。jieba 詞典 dict.txt 是 jieba 作者採集了超大規模的語料數據,統計得到的。有 5M,包含349,046條詞語。每一行對應一個詞語,包含詞語 詞數 詞性三部分。

2、載入詞典

開發者可以指定自己自定義的詞典,以便包含 jieba 詞庫裏沒有的詞。雖然 jieba 有新詞識別能力,但是自行添加新詞可以保證更高的正確率。

 jieba.load_userdict(file_name)

詞典格式和 dict.txt 一樣,一個詞佔一行;每一行分三部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可顛倒。

file_name 爲文件類對象或自定義詞典的路徑,若爲路徑或二進制方式打開的文件,則文件必須爲 UTF-8 編碼。

詞頻省略時使用自動計算的能保證分出該詞的詞頻。

例如:

創新辦 3 i
雲計算 5
凱特琳 nz
臺中

更改分詞器(默認爲 jieba.dt)的 tmp_dircache_file 屬性,可分別指定緩存文件所在的文件夾及其文件名,用於受限的文件系統。

代碼示例:

#encoding=utf-8
import sys
sys.path.append("../")
import jieba
import jieba.posseg as pseg

test_sent = (
"李小福是創新辦主任也是雲計算方面的專家; 什麼是八一雙鹿\n"
"例如我輸入一個帶“韓玉賞鑑”的標題,在自定義詞庫中也增加了此詞爲N類\n"
"「臺中」正確應該不會被切開。mac上可分出「石墨烯」;此時又可以分出來凱特琳了。"
)
words = jieba.cut(test_sent)
print("使用默認詞庫:\n {}".format('/'.join(words)))
print("="*40)

jieba.load_userdict("userdict.txt")
"""
userdict.txt
雲計算 5
李小福 2 nr
創新辦 3 i
pip_install 3 eng
好用 300
韓玉賞鑑 3 nz
八一雙鹿 3 nz
臺中
凱特琳 nz
Edu Trust認證 2000
"""
jieba.add_word('石墨烯')
jieba.add_word('凱特琳')
jieba.del_word('自定義詞')

words = jieba.cut(test_sent)
print("加載自定義詞庫後: \n{}".format('/'.join(words)))
print("="*40)

# 帶有詞性的分詞
result = pseg.cut(test_sent)

for w in result:
    print(w.word, "/", w.flag, ", ", end=' ')
print("\n" + "="*40)

terms = jieba.cut('pip_install is great')
print('/'.join(terms))
terms = jieba.cut('python 的正則表達式是好用的')
print('/'.join(terms))
print("="*40)

使用默認詞庫::
李小福 / 是 / 創新 / 辦 / 主任 / 也 / 是 / 雲 / 計算 / 方面 / 的 / 專家 /

加載自定義詞庫後:
李小福 / 是 / 創新辦 / 主任 / 也 / 是 / 雲計算 / 方面 / 的 / 專家 /

3、調整詞典

使用 add_word(word, freq=None, tag=None)del_word(word) 可在程序中動態修改詞典。

使用 get_FREQ(word) 用來統計當前詞的詞頻。

使用 suggest_freq(segment, tune=True) 可調節單個詞語的詞頻,使其能(或不能)被分出來。

注意:自動計算的詞頻在使用 HMM 新詞發現功能時可能無效。

代碼示例:

# test frequency tune
testlist = [
('今天天氣不錯', ('今天', '天氣')),
('如果放到post中將出錯。', ('中', '將')),
('我們中出了一個叛徒', ('中', '出')),
]

for sent, seg in testlist:
    print('/'.join(jieba.cut(sent, HMM=False)))
    word = ''.join(seg)
    print('%s Before: %s, After: %s' % (word, jieba.get_FREQ(word), jieba.suggest_freq(seg, True)))
    print('/'.join(jieba.cut(sent, HMM=False)))
    print("-"*40)

今天天氣 / 不錯
今天天氣 Before: 3, After: 0
今天 / 天氣 / 不錯

如果 / 放到 / post / 中將 / 出錯 /
中將 Before: 763, After: 494
如果 / 放到 / post / 中 / 將 / 出錯 /。

我們 / 中 / 出 / 了 / 一個 / 叛徒
中出 Before: 3, After: 3
我們 / 中 / 出 / 了 / 一個 / 叛徒

通過用戶自定義詞典來增強歧義糾錯能力 [2]

參考資料

[1] jieba 分詞: https://github.com/fxsjy/jieba

[2] 用戶自定義詞典: https://github.com/fxsjy/jieba/issues/14

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/iYmwqXt6HeKHSnWdth2YMA