這是全棧資料工程師養成攻略系列教程的第十七期:17 NLP 使用jieba分詞處理文字。
我們對NLP是什麼和做什麼,以及和NLP領域相關的內容和應用有了一個大致的概覽,現在讓我們通過Python中的jieba中文分詞
來進行部分實現。
jieba中文分詞
中文分詞是中文NLP的第一步,一個優秀的分詞系統取決於足夠的語料和完善的模型,很多機構和公司也都會開發和維護自己的分詞系統。這裡推薦的是一款完全開源、簡單易用的分詞工具,jieba中文分詞
。官網在這裡,github.com/fxsjy/jieba,裡面提供了詳細的說明文件。雖然jieba分詞的效能並不是最優秀的,但它開源免費、使用簡單、功能豐富,並且支援多種程式語言實現。
以下我們使用Python中的jieba分詞完成一些基礎NLP任務,如果對jieba分詞感興趣,希望瞭解更多內容,可以參考官方使用文件。首先沒有jieba分詞的話需要安裝,使用pip即可。
pip install jieba複製程式碼
中文分詞
中文分詞的模型實現主要分類兩大類:基於規則和基於統計。
基於規則是指根據一個已有的詞典,採用前向最大匹配、後向最大匹配、雙向最大匹配等人工設定的規則來進行分詞。例如對於“上海自來水來自海上”這句話,使用前向最大匹配,即從前向後掃描,使分出來的詞存在於詞典中並且儘可能長,則可以得到“上海/自來水/來自/海上”。這類方法思想簡單且易於實現,對資料量的要求也不高。當然,分詞所使用的規則可以設計得更復雜,從而使分詞效果更理想。但是由於中文博大精深、語法千變萬化,很難設計足夠全面而通用的規則,並且具體的上下文語境、詞語之間的搭配組合也都會影響到最終的分詞結果,這些挑戰都使得基於規則的分詞模型愈發力不從心。
基於統計是從大量人工標註語料中總結詞的概率分佈以及詞之間的常用搭配,使用有監督學習訓練分詞模型。對於“上海自來水來自海上”這句話,一個最簡單的統計分詞想法是,嘗試所有可能的分詞方案,因為任何兩個字之間,要麼需要切分,要麼無需切分。對於全部可能的分詞方案,根據語料統計每種方案出現的概率,然後保留概率最大的一種。很顯然,“上海/自來水/來自/海上”的出現概率比“上海自/來水/來自/海上”更高,因為“上海”和“自來水”在標註語料中出現的次數比“上海自”和“來水”更多。
其他常用的基於統計的分詞模型還有HMM(Hidden Markov Model)和CRF(Conditional Random Field)等,以及將中文分詞視為序列標註問題(BEMS,即將每個字標註成Begin、End、Middle、Single中的一個,輸入字序列,輸出標籤序列),進而使用有監督學習、深度神經網路等模型進行中文分詞。
jieba分詞結合了基於規則和基於統計兩類方法。首先基於字首詞典進行詞圖掃描,字首詞典是指詞典中的詞按照字首包含的順序排列,例如詞典中出現了“上”,之後以“上”開頭的詞都會出現在這一塊,例如“上海”,進而會出現“上海市”,從而形成一種層級包含結構。如果將詞看作節點,詞和詞之間的分詞符看作邊,那麼一種分詞方案則對應著從第一個字到最後一個字的一條分詞路徑。因此,基於字首詞典可以快速構建包含全部可能分詞結果的有向無環圖,這個圖中包含多條分詞路徑,有向是指全部的路徑都始於第一個字、止於最後一個字,無環是指節點之間不構成閉環。基於標註語料,使用動態規劃的方法可以找出最大概率路徑,並將其作為最終的分詞結果。
jieba提供了三種分詞模式:
- 精確模式:試圖將句子最精確地切開,適合文字分析;
- 全模式:把句子中所有可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;
- 搜尋引擎模式:在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。
以下程式碼使用jieba實現中文分詞,使用jieba.cut()
函式並傳入待分詞的文字字串即可,使用cut_all
引數控制選擇使用全模式還是精確模式,預設為精確模式。如果需要使用搜尋引擎模式,使用jieba.cut_for_search()
函式即可。執行以下程式碼之後,jieba首先會載入自帶的字首詞典,然後完成相應的分詞任務。
import jieba
seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
# join是split的逆操作
# 即使用一個拼接符將一個列表拼成字串
print("/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("/ ".join(seg_list)) # 精確模式
seg_list = jieba.cut("他來到了網易杭研大廈") # 預設是精確模式
print("/ ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業於中國科學院計算所,後在日本京都大學深造") # 搜尋引擎模式
print("/ ".join(seg_list))複製程式碼
關鍵詞提取
jieba實現了TF-IDF
和TextRank
這兩種關鍵詞提取演算法,直接呼叫即可。當然,提取關鍵詞的前提是中文分詞,所以這裡也會使用到jieba自帶的字首詞典和IDF權重詞典。
import jieba.analyse
# 字串前面加u表示使用unicode編碼
content = u'中國特色社會主義是我們黨領導的偉大事業,全面推進黨的建設新的偉大工程,是這一偉大事業取得勝利的關鍵所在。黨堅強有力,事業才能興旺發達,國家才能繁榮穩定,人民才能幸福安康。黨的十八大以來,我們黨堅持黨要管黨、從嚴治黨,凝心聚力、直擊積弊、扶正祛邪,黨的建設開創新局面,黨風政風呈現新氣象。習近平總書記圍繞從嚴管黨治黨提出一系列新的重要思想,為全面推進黨的建設新的偉大工程進一步指明瞭方向。'
# 第一個引數:待提取關鍵詞的文字
# 第二個引數:返回關鍵詞的數量,重要性從高到低排序
# 第三個引數:是否同時返回每個關鍵詞的權重
# 第四個引數:詞性過濾,為空表示不過濾,若提供則僅返回符合詞性要求的關鍵詞
keywords = jieba.analyse.extract_tags(content, topK=20, withWeight=True, allowPOS=())
# 訪問提取結果
for item in keywords:
# 分別為關鍵詞和相應的權重
print item[0], item[1]
# 同樣是四個引數,但allowPOS預設為('ns', 'n', 'vn', 'v')
# 即僅提取地名、名詞、動名詞、動詞
keywords = jieba.analyse.textrank(content, topK=20, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))
# 訪問提取結果
for item in keywords:
# 分別為關鍵詞和相應的權重
print item[0], item[1]複製程式碼
對於所提取的關鍵詞以及權重,將每個關鍵詞的權重作為文字大小,便可以進行字元雲視覺化。
詞性標註
jieba在進行中文分詞的同時,還可以完成詞性標註任務。根據分詞結果中每個詞的詞性,可以初步實現命名實體識別,即將標註為nr
的詞視為人名,將標註為ns
的詞視為地名等。所有標點符號都會被標註為x
,所以可以根據這個去除分詞結果中的標點符號。
# 載入jieba.posseg並取個別名,方便呼叫
import jieba.posseg as pseg
words = pseg.cut("我愛北京天安門")
for word, flag in words:
# 格式化模版並傳入引數
print('%s, %s' % (word, flag))複製程式碼
視訊連結:使用jieba分詞處理文字