Skip to content

[NLP][Python] 中文斷詞最方便的開源工具之一: Jieba

Last Updated on 2021-03-29 by Clay

『斷詞』(或者你習慣講『分詞』)的重要性在中文 NLP 當中幾乎可說是無人不知、無人不曉。若是今天我們要進行中文的句法分析,試想:若是我們連句子當中有哪些『詞』都不知道,只知道有什麼樣的『字』存在於句子中,那我們該如何去分析這個句子?

於是在進行中文處理時,『斷詞』的工作可謂是必不可少。
當然,搞不好往後的中文分析都是使用深度學習,到了那一天或許也不再需要斷詞啦,不過現階段還是要的。

Jieba,就是一個開源的、可在 Github 上找到的斷詞專案。主要功能當然就是斷詞,其處理速度可是非常非常地快,遠比我使用的其他斷詞工具更迅速。不只如此,我個人認為它的準確率也相當之高,在某些類型的文件甚至還贏過台灣中研院開發的 CKIP。

其內部的工作原理如開發者的 README 所示:

  1. 使用前綴詞典進行詞圖掃描,生成所有成詞情況的有向無環圖(DAG, directed acyclic graph )
  2. 使用動態規劃查找最大概率路徑
  3. 使用 HMM 模型(Hidden Markov Models)找出『未登錄詞』

如果你使用 Python 來實現 Jieba 的功能,你可以直接使用 pip 安裝。

pip3 install jieba

以下我便開始紀錄關於如何使用 Jieba 的心得,若想觀看開發者的 Github: https://github.com/fxsjy/jieba

若不是使用 Python 的讀者,可以參考 Github 上的『其他語言實現』。


分詞模式

### 註:以下我所提及的『斷詞』即為『分詞』###

jiaba.cut() 為我們最常使用的功能,我們分別可以輸入『待斷詞文本』、『cut_all 全模式是否啟用』、『HMM 模型是否啟用』 三個參數。其中只有待斷詞文本是一定要輸入,cut_all 預設是關閉的、 HMM 模型預設是啟用的。

我們以下使用 Github 上的範例來進行,不過我這裡使用的是繁體。

# -*- coding: utf-8 -*-
import jieba

text = '我來到北京清華大學'
print('預設:', '|'.join(jieba.cut(text, cut_all=False, HMM=True)))
print('全關閉:', '|'.join(jieba.cut(text, cut_all=False, HMM=False)))
print('全關閉:', '|'.join(jieba.cut(text, cut_all=True, HMM=True)))


Output:

預設: 我|來到|北京|清華|大學
全關閉: 我|來到|北京|清華|大學
全關閉: 我來|來到|北京|清華|華大|大學
搜尋引擎: 我|來到|北京|清華|大學

jieba.cut() 返回的結果是一個可迭代的 generator,可以像我上述的範例一般使用 join() 來加入分隔符號。你也可以使用 jieba.lcut() 來直接返回一個 list。


使用者詞典

有些時候,我們使用 Jieba 這種斷詞工具難免會碰到斷詞器對我們的文本表現差強人意的情況。有些時候是因為有太多專業詞彙在我們的文本裡頭,這時候,也許我們加入一些我們自己的使用者詞典比較好。

以下我們來看個簡單的範例:

總統蔡英文論文風波延燒後,最新民調今日出爐!據親藍民調公布結果,蔡英文支持度45%,遙遙領先韓國瑜的33%,兩人差距擴大到12個百分點。顯示論文門風波,並未重創小英聲望。

這是我今天(2019/09/23)從 Google News 上擷取的一份簡單的報導,我們把這段文本丟進 Jieba 進行斷詞。

['總統', '蔡英文', '論文', '風波', '延燒', '後', ',', '最', '新', '民調', '今日', '出爐', '!', '據', '親藍', '民調', '公布', '結果', ',', '蔡英文', '支持度', '45%', ',', '遙遙領先', '韓國', '瑜', '的', '33%', ',', '兩人', '差距', '擴大到', '12', '個', '百分點', '。', '顯示', '論文', '門', '風波', ',', '並未', '重創', '小英', '聲望', '。']

大部分的斷詞結果都還不錯,唯一最大的問題就是斷詞結果將『韓國瑜』斷成了『韓國』、『瑜』。

這怎麼可以!我可是鋼鐵韓粉欸!

氣急攻心的我一怒之下馬上新建了一個使用者自訂的詞表 userDict.txt,並在裡面加入了詞彙和詞頻(省略的情況程式會自動計算應有的詞頻)。

韓國瑜 3000

然後再次回到我的程式碼,加入以下這行:

jieba.load_userdict('userDict.txt')


再次進行斷詞:

print(jieba.lcut(text))


Output:

['總統', '蔡英文', '論文', '風波', '延燒', '後', ',', '最', '新', '民調', '今日', '出爐', '!', '據', '親藍', '民調', '公布', '結果', ',', '蔡英文', '支持度', '45%', ',', '遙遙領先', '韓國瑜', '的', '33%', ',', '兩人', '差距', '擴大到', '12', '個', '百分點', '。', '顯示', '論文', '門', '風波', ',', '並未', '重創', '小英', '聲望', '。']

沒錯!我大宇宙大統領的韓總的名字終於被 Jieba 斷對啦!(發病中)


詞性標記 (POS)

要使用詞性標記 (POS),我們需要另外 import jieba 底下的 pseg

使用方法如下:

# -*- coding: utf-8 -*-
import jieba
import jieba.posseg as pseg

text = '我來到北京清華大學'
words = pseg.cut(text)
for word, flag in words:
    print(word, flag)


Output:

我 r
來到 x
北京 ns
清華 x
大學 x

至於每個詞性代表著什麼,我在網路上找到了一個網站,也許可以參考一下: https://www.cnblogs.com/chenbjin/p/4341930.html


關鍵字抽取

根據 README 的說明,關鍵字抽取的方式是使用 TF-IDF 的計算方法。這種方法我有實做過,也許哪天可以分享一下。

使用方法如下,跟 POS 一樣,我們需要 import jieba.analyse 這個額外的套件。

# -*- coding: utf-8 -*-
import jieba
import jieba.analyse

text = '總統蔡英文論文風波延燒後,最新民調今日出爐!據親藍民調公布結果,蔡英文支持度45%,遙遙領先韓國瑜的33%,兩人差距擴大到12個百分點。顯示論文門風波,並未重創小英聲望。'
tags = jieba.analyse.extract_tags(text, topK=5)
print(tags)


Output:

['蔡英文', '論文', '風波', '民調', '小英']

topK 為返回 TF-IDF 權重最大的關鍵詞, Default 為 20。在這裡我只設定了 5。


討論

Jieba 的功能還有很多,包括所謂的『並行分詞』等等提升斷詞速度的選項。這些就留給感興趣的人去試一試了。

另外,如果你覺得直接下載下來的 Jieba 對於繁體中文的支援不好,Github 其實也有提供繁體的中文詞典: https://raw.githubusercontent.com/fxsjy/jieba/master/extra_dict/dict.txt.big

再次說明,我認為各家的斷詞器其實針對不同的語料其實都各有優點,這很可能跟底層的訓練資料有關,大家還是多多嘗試不同的斷詞器,這才能找到最適合自己的工具哦!

Tags:

Leave a Reply