Last Updated on 2021-03-29 by Clay
『斷詞』(或者你習慣講『分詞』)的重要性在中文 NLP 當中幾乎可說是無人不知、無人不曉。若是今天我們要進行中文的句法分析,試想:若是我們連句子當中有哪些『詞』都不知道,只知道有什麼樣的『字』存在於句子中,那我們該如何去分析這個句子?
於是在進行中文處理時,『斷詞』的工作可謂是必不可少。
當然,搞不好往後的中文分析都是使用深度學習,到了那一天或許也不再需要斷詞啦,不過現階段還是要的。
Jieba,就是一個開源的、可在 Github 上找到的斷詞專案。主要功能當然就是斷詞,其處理速度可是非常非常地快,遠比我使用的其他斷詞工具更迅速。不只如此,我個人認為它的準確率也相當之高,在某些類型的文件甚至還贏過台灣中研院開發的 CKIP。
其內部的工作原理如開發者的 README 所示:
- 使用前綴詞典進行詞圖掃描,生成所有成詞情況的有向無環圖(DAG, directed acyclic graph )
- 使用動態規劃查找最大概率路徑
- 使用 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
再次說明,我認為各家的斷詞器其實針對不同的語料其實都各有優點,這很可能跟底層的訓練資料有關,大家還是多多嘗試不同的斷詞器,這才能找到最適合自己的工具哦!