Python - 知名 Jieba 中文斷詞工具教學
今天要介紹的這個算是很知名的中文斷詞工具,這個是大陸人發明的工具,並且將其開源在 GitHub 上,而且有積極維護中,非常不錯。但是可想而知它的這個工具對簡體中文分詞會比較準確,繁體中文雖然用這工具也還可以,但是有一些像是台灣用語就比較難斷得很好。
Jieba 安裝教學
conda 安裝
1 | conda install -c conda-forge jieba |
pip 安裝
1 | pip install jieba |
適合的 Python 版本 3 或 2 都支援,但是建議大家還是盡快使用 Python3,畢竟 Python2 已經官方公佈不支援了。
Jieba 原理介紹
Jieba 斷詞主要是结合:
-
規則斷詞
主要是透過詞典,在對句子進行斷詞的時候,將句子的每個字與詞典中的詞進行匹配,找到則斷詞,否則無法斷詞。
-
統計斷詞
主要是看如果相連的字在不同的文本中出現的次數越多,就推斷這相連的字很可能就是一個詞。因此就可以利用字與字相鄰出现的頻率來做統計。當高於某一個臨界值時,便可認為此字組是一個詞語。
透過以上兩種策略,再根據 Jieba 文檔的技術原理說明:
-
使用前綴詞典進行詞圖掃描,生成所有成詞情況的有向無環圖(DAG, directed acyclic graph )
例如:上 => 上海 => 上海市
再透過,使用動態規劃查找最大概率路徑
-
使用 HMM 模型(Hidden Markov Models)找出『未登錄詞』
所謂 HMM 模型就是一種統計斷詞的方法,未登錄詞就是想成詞典中沒有這種詞,必須經過統計來得知新的詞語。
這邊就不在多講裡面技術的演算法是怎樣,有興趣的話可以根據關鍵字去查詢演算法。
Jieba 斷詞模式
最著名的功能就是提供斷詞模式,主要分為
-
精確模式
將句子最精確的切開,適合文本分析
-
全模式
把句子中所有的可以成詞的詞語都斷出来,速度非常快。
-
搜索引擎模式
在精確模式的基礎上,對長的詞語再次切分,提高召回率,適合用於搜索引擎分詞。
操作方式:
- 透過 jieba.cut () 來進行斷詞,cut_all 參數為 True 的話為全模式,預設為 False,也就是精確模式
- jibea.cut_for_search () 是搜索引擎模式
- cut ()、cur_for_search () 返回的結構都是一个可迭代的 generator,因此使用 for 迴圈來取得每個斷詞。
簡體中文測試
1 | import jieba |
輸出如下:
1 | 我/来自/北京/清华大学 |
可以看出其實是滿準確的,尤其是精確模式,斷詞斷得很正確,而這輸出結果也可以看出精確模式、全模式、搜索引擎模式差別在哪。
繁體中文測試
1 | import jieba |
輸出如下:
1 | 我來/自/北京/清華大學 |
將簡體中文成繁體中文,可以看出精確模式下,第三句每天發技術文章斷不準確,但其他句斷的前面簡體中文一樣。
jieba.lcut () 示範
也可以使用 lcut (),意思跟 cut () 是一樣的,只是返回的型態變成 list,方便使用。
1 | import jieba |
輸出如下:
1 | ['我', '来自', '北京', '清华大学'] |
台灣新聞文檔測試
這是我去拿最近的新聞稿的文字:
1 | 蘇貞昌表示,春節期間中國武漢肺炎疫情急遽升高,他在年假第一天就到中央流行疫情指揮中心聽取簡報,並宣布提升到二級開設。年假期間,衛福部及相關機關幾乎都放棄休假,每天監控及因應各項疫情,並宣布防疫資源整備情形及最新防疫作為,隨時讓國人瞭解最新疫情發展。因為資訊透明,應變迅速,讓國人感受到「有政府,可放心」,感謝陳其邁副院長費心督導,對於年假期間各防疫機關人員的堅守崗位,也表示肯定與感謝。 |
用 Jieba 測試台灣用語的繁體中文效果如何:
1 | import jieba |
輸出如下:
1 | ['蘇貞昌', '表示', ',', '春節', '期間', '中國', '武漢', '肺炎', '疫情', '急遽', '升高', ',', '他', '在', '年', '假', '第一天', '就', '到', '中央', '流行', '疫情', '指揮', '中心', '聽取', '簡報', ',', '並', '宣布', '提升', '到', '二級', '開設', '。', '年', '假期', '間', ',', '衛福部', '及', '相關', '機關', '幾乎', '都', '放棄', '休假', ',', '每天', '監控及', '因應', '各項', '疫情', ',', '並', '宣布', '防疫', '資源', '整備', '情形', '及', '最新', '防疫', '作為', ',', '隨時', '讓', '國人', '瞭解', '最新', '疫情', '發展', '。', '因為', '資訊', '透明', ',', '應變', '迅速', ',', '讓', '國人', '感受', '到', '「', '有', '政府', ',', '可', '放心', '」', ',', '感謝', '陳', '其邁', '副', '院長', '費心督導', ',', '對', '於', '年', '假期', '間', '各', '防疫', '機關', '人員', '的', '堅守崗位', ',', '也', '表示', '肯定', '與', '感謝', '。'] |
發現以下幾點事情:
- 武漢肺炎、年假、陳其邁,這些詞沒斷好,推斷可能大陸用語沒有這樣的用法,此外台灣的人名也一定會是新詞沒辦法被斷好。
- 標點符號會自動被斷出來
還好,Jieba 提供自定義詞典的功能,用來避免以上的情況。
Jieba 自定義詞典
-
如果 Jieba 內建詞庫沒有你要的詞,可以建立自定義的詞典
讓 Jieba 根據你自定義的詞典來斷出你想要的詞。雖然可能會覺得這樣不就很 Hard Code 嗎?沒錯就是這樣,因為大部分的情況下雖說是依賴 Jieba 斷詞的能力,但在特殊的名詞或者台灣用語可以採用該方法
-
用法:jieba.load_userdict (file_path)
file_path 為自定義詞典的檔案路徑
-
自定義詞典格式
一個词占一行,每一行分三部分:詞語、詞頻(可省略)、磁性(可省略),用空格隔開,顺序不可錯誤。file 必須為 UTF-8 編碼。
詞頻省略的話 Jieba 內建會自動計算,保證可以分出你自定義的詞頻。簡單來說,你可以想成,你自定義的詞語一定是優先度最大,儘管跟其他有衝突,你定義的 Jieba 一定會優先斷出來,保證正確性。
根據以上的新聞稿,我們將武漢肺炎、年假、陳其邁,加入自定義詞典試試看有沒有辦法成功斷詞出來。
在專案路徑下新增一個檔案叫做:userdict.txt
內容如下:
1 | 武漢肺炎 |
程式碼如下:
1 | import jieba |
輸出結果:
1 | ['蘇貞昌', '表示', ',', '春節', '期間', '中國', '武漢肺炎', '疫情', '急遽', '升高', ',', '他', '在', '年假', '第一天', '就', '到', '中央', '流行', '疫情', '指揮', '中心', '聽取', '簡報', ',', '並', '宣布', '提升', '到', '二級', '開設', '。', '年', '假期', '間', ',', '衛福部', '及', '相關', '機關', '幾乎', '都', '放棄', '休假', ',', '每天', '監控及', '因應', '各項', '疫情', ',', '並', '宣布', '防疫', '資源', '整備', '情形', '及', '最新', '防疫', '作為', ',', '隨時', '讓', '國人', '瞭解', '最新', '疫情', '發展', '。', '因為', '資訊', '透明', ',', '應變', '迅速', ',', '讓', '國人', '感受', '到', '「', '有', '政府', ',', '可', '放心', '」', ',', '感謝', '陳其邁', '副', '院長', '費心督導', ',', '對', '於', '年', '假期', '間', '各', '防疫', '機關', '人員', '的', '堅守崗位', ',', '也', '表示', '肯定', '與', '感謝', '。'] |
可以看出,年假、武漢肺炎、陳其邁被成功斷出來,但你可能會發現年假期間沒有被斷好,所以可以考慮在把年假期間加入自定義詞典裡面。
基本上,我自己覺得在還沒有自定義詞典的話,大部分的詞語也算斷得不錯,再加入自定義詞典差不多也夠了。
說實在如果只是要做特定領域的機器人,像是現在很夯的 Line Bot、Messenger Bot,且沒有很精確的要求,其實很多機器人它可能只是用到句子斷詞的功能,藉此找到該句子的一些關鍵字,而根據關鍵字,機器人再回答相對應的句子。所以,有時候你會發現你如果只打一個關鍵字,機器人還是回你同樣的話,通常就是這樣設計的。
而除了自定義詞典,也可以在程式碼中動態加入自定義的詞,來幫助斷詞正確性提高:
-
jieba.add_word (‘武漢肺炎’)
-
jieba.suggest_freq (‘武漢肺炎’, tune=True)
tune 的參數代表該詞語要不要被成功斷出來。
Jieba 透過 TF-IDF 找出句子關鍵字
此外,Jieba 也有提供根據 TF-IDF 算法來找出句子的關鍵字。
程式碼如下:
1 | import jieba.analyse |
jieba.analyse.extract_tags 主要有以下的參數:
- sentence 為句子
- topK 代表返回 TF-IDF 權重最大的關鍵字,默認為 20
- withWeight 代表是否返回關鍵字權重值,默認為 False
- allowPOS 代表指定詞性,默認為空,也就是不篩選
輸出如下:
1 | word: 疫情 tf-idf: 0.4687853402985507 |
可以看到疫情的最高,實際上句子確實也是疫情出現最多次~符合關鍵字。
此外,除了 TF-IDF 算法,還有提供基於 TextRank 算法的關鍵字抽取,這邊就不多介紹,有興趣的話可以看文檔。
Jieba 詞性標註功能
透過 jiba.posseg.cut () 可以將句子中的每個斷詞進行詞性標註。
程式碼:
1 | words = jieba.posseg.cut('我喜欢写程式') |
輸出如下:
1 | 我 r |
至於旁邊英文字母代表甚麼詞性,需要參考官方提供的說明:
標籤 | 含意 | 標籤 | 含意 | 標籤 | 含意 | 標籤 | 含意 |
---|---|---|---|---|---|---|---|
n | 普通名词 | f | 方位名词 | s | 处所名词 | t | 时间 |
nr | 人名 | ns | 地名 | nt | 机构名 | nw | 作品名 |
nz | 其他专名 | v | 普通动词 | vd | 动副词 | vn | 名动词 |
a | 形容词 | ad | 副形词 | an | 名形词 | d | 副词 |
m | 数量词 | q | 量词 | r | 代词 | p | 介词 |
c | 连词 | u | 助词 | xc | 其他虚词 | w | 标点符号 |
PER | 人名 | LOC | 地名 | ORG | 机构名 | TIME | 时间 |
總結
總的來說,身為一個開源工具提供這麼多功能還是很棒的,儘管對於繁體中文或台灣用語不是那麼好,不過我認為解決方法就是:
-
https://github.com/ldkrsi/jieba-zh_TW
這個是有人將 Jieba 內建的詞典改成台灣繁體版本,因此可以考慮用這個 jieba 工具,缺點就是沒辦法跟著 Jieba 工具持續更新
-
用自定義詞典來解決台灣繁體用語
-
使用台灣中研院開源的 CkipTagger,這個我還沒用過,聽說繁體中文斷詞很不錯,改天試試看,在發文紀錄 XD
此外,官方文檔也有提供多種程式語言的版本,非常的不錯。
Jieba 斷詞的速度也滿快的,當然如果參考其他語言的實作可能會更快。總得來說,如果是做簡單的機器人且沒有那麼在乎準確性,使用 Jieba 是還不錯的選擇,此外也可以用在文檔分析上,幫助斷詞以便之後進行更進一步的操作。