1. 程式人生 > >【NLP】中文處理前提--jieba詳解

【NLP】中文處理前提--jieba詳解

介紹

\quad\quad在自然語言處理中,中文處理技術比西文處理技術要落後很大一段距離,許多西文的處理方法中文不能直接採用,就是因為中文必需有分詞這道工序。

\quad\quad當我們進行自然語言處理的時候,大部分情況下,詞彙是我們對句子和文章理解的基礎,因此需要一個工具去把完整的文字中分解成粒度更細的詞。

中文分詞是其他中文處理的基礎

Python3 jieba庫的安裝

  • 直接命令列輸入:pip install jieba
  • 百度PyPI,搜尋下載jieba包,放在命令列啟動目錄下,輸入pip install (+ jieba包的包名全稱)

jieba主要功能

1. jieba分詞的特點

支援三種分詞模式:

  • 精確模式,試圖將句子最精確地切開,適合文字分析;
  • 全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;
  • 搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。

支援繁體分詞

支援自定義詞典

MIT 授權協議

2. 分詞函式

\quad\quadjieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可以使用 for 迴圈來獲得分詞後得到的每一個詞語(unicode) 支援三種分詞模式:

jieba.cut(將包含中文字元的整個句子分成單獨分詞)

語法:

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

引數說明:

  • sentence:需要分詞的句子
  • cut_all:引數用來控制是否採用全模式
  • HMM:引數用來控制是否使用 HMM 模型

例項:

import jieba
# 分詞
# 全模式
cut1 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區", cut_all=True)
print("全模式: "+" / ".join(cut1))
# 精確模式
cut2 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區", cut_all=
False) print("精確模式: "+" / ".join(cut2)) # 預設模式--精確模式 cut3 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" ) print("預設模式: "+" / ".join(cut3))

執行結果:

全模式: 雲南 / 雲南省 / 昆明 / 昆明市 / 昆明 / 明理 / 理工 / 理工大 / 理工大學 / 工大 / 大學 / 是 / 個 / 美麗 / 的 / 學校 /  /  / 學校 / 在 / 呈貢 / 區
精確模式: 雲南省 / 昆明市 / 昆明 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區
預設模式: 雲南省 / 昆明市 / 昆明 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區

jieba.cut_for_search(搜尋引擎模式)

語法:

jieba.cut_for_search(sentence, HMM=True)

引數說明:

  • sentence:需要分詞的句子
  • HMM:引數用來控制是否使用 HMM 模型

例項:

# 搜尋引擎模式
cut4 = jieba.cut_for_search("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print("搜尋引擎模式: "+" / ".join(cut4))

執行結果:

搜尋引擎模式: 雲南 / 雲南省 / 昆明 / 昆明市 / 昆明 / 理工 / 工大 / 大學 / 理工大 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區

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

例項:

cut5 = jieba.lcut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print(type(cut5))
print("預設模式: "+" / ".join(cut5))
# 搜尋引擎模式
cut6 = jieba.lcut_for_search("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print(type(cut6))
print("搜尋引擎模式: "+" / ".join(cut6))

執行結果:

<class 'list'>
預設模式: 雲南省 / 昆明市 / 昆明 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區
<class 'list'>
搜尋引擎模式: 雲南 / 雲南省 / 昆明 / 昆明市 / 昆明 / 理工 / 工大 / 大學 / 理工大 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區

3. 新增使用者自定義詞典

\quad\quad很多時候我們需要針對自己的場景進行分詞,會有一些領域內的專有詞彙。開發者可以指定自己自定義的詞典,以便包含 jieba 詞庫裡沒有的詞。雖然 jieba 有新詞識別能力,但是自行新增新詞可以保證更高的正確率。

用法:

  • 1.可以用jieba.load_userdict(file_name)載入使用者字典,其中file_name 為檔案類物件或自定義詞典的路徑
  • 2.少量的詞彙可以自己用下面方法手動新增:
  • \quad\quadadd_word(word, freq=None, tag=None)del_word(word)在程式中動態修改詞典
  • \quad\quadsuggest_freq(segment, tune=True) 可調節單個詞語的詞頻,使其能(或不能)被分出來。

詞典格式:

  • 詞典是txt檔案,一個詞佔一行;
  • 每一行分三部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可顛倒;
  • file_name若為路徑或二進位制方式開啟的檔案,則檔案必須為 UTF-8 編碼。

注:

  • 詞典構建方式:一般都是基於jieba分詞之後的效果進行人工干預的

例如:dict.txt

雲南省 nt
昆明市 nt
昆明理工大學 2 nt
是個
美麗的 a
學校
在
呈貢區

例項1:

import jieba

cut1 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print("加入詞典前: "+" / ".join(cut1))

jieba.load_userdict('dict.txt')

cut2 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print("加入詞典後: "+" / ".join(cut2))

執行結果:

加入詞典前: 雲南省 / 昆明市 / 昆明 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區
加入詞典後: 雲南省 / 昆明市 / 昆明理工大學 / 是個 / 美麗的 / 學校 / , / 學校 / 在 / 呈貢區

例項2:

import jiieba

print('/'.join(jieba.cut('如果放到舊字典中將出錯。', HMM=False)))

jieba.suggest_freq(('中', '將'), True)

print('/'.join(jieba.cut('如果放到舊字典中將出錯。', HMM=False)))

執行結果:

如果/放到/舊/字典/中將/出錯/。
如果/放到/舊/字典/中/將/出錯/。

例項3:

import jieba

cut1 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print("動態修改詞典前: "+" / ".join(cut1))

jieba.add_word('昆明理工大學')
jieba.add_word('呈貢區')
jieba.del_word('昆明市')

cut2 = jieba.cut("雲南省昆明市昆明理工大學是個美麗的學校,學校在呈貢區" )
print("動態修改詞典後: "+" / ".join(cut2))

執行結果:

動態修改詞典前: 雲南省 / 昆明市 / 昆明 / 理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢 / 區
動態修改詞典後: 雲南省 / 昆明 / 市 / 昆明理工大學 / 是 / 個 / 美麗 / 的 / 學校 / , / 學校 / 在 / 呈貢區

例項4:

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

for sent, seg in testlist:
    print('/'.join(jieba.cut(sent, HMM=False)))
    word = ''.join(seg)
    print('%s 調節單個詞語的詞頻前的詞頻: %s, 調節單個詞語的詞頻後的詞頻: %s' % (word, jieba.get_FREQ(word), jieba.suggest_freq(seg, True)))
    print('/'.join(jieba.cut(sent, HMM=False)))
    print("-"*40)

執行結果:

今天天氣/不錯
今天天氣 調節單個詞語的詞頻前的詞頻: 3, 調節單個詞語的詞頻後的詞頻: 0
今天/天氣/不錯
----------------------------------------
如果/放到/post/中將/出錯/。
中將 調節單個詞語的詞頻前的詞頻: 763, 調節單個詞語的詞頻後的詞頻: 494
如果/放到/post/中/將/出錯/。
----------------------------------------
我們/中/出/了/一個/叛徒
中出 調節單個詞語的詞頻前的詞頻: 3, 調節單個詞語的詞頻後的詞頻: 3
我們/中/出/了/一個/叛徒
----------------------------------------

4. 關鍵詞提取

import jieba.analyse

(1)基於 TF-IDF 演算法的關鍵詞抽取

語法:

jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())

引數說明:

  • sentence 為待提取的文字
  • topK 為返回幾個 TF/IDF 權重最大的關鍵詞,預設值為 20
  • withWeight 為是否一併返回關鍵詞權重值,預設值為 False
  • allowPOS 僅包括指定詞性的詞,預設值為空,即不篩選

例項1:

import jieba.analyse as analyse
lines = open('NBA.txt', encoding='utf-8').read()
print("  ".join(analyse.extract_tags(lines, topK=20, withWeight=False, allowPOS=())))

執行結果:

韋少  杜蘭特  全明星  全明星賽  MVP  威少  正賽  科爾  投籃  勇士  球員  斯布魯克  更衣櫃  NBA  三連莊  張衛平  西部  指導  雷霆  明星隊

例項2:

import jieba.analyse as analyse
lines1 = open('西遊記.txt',encoding='gb18030').read()
print("  ".join(analyse.extract_tags(lines1, topK=20, withWeight=False, allowPOS=())))
lines2 = open('西遊記語錄.txt',encoding='gb18030').read()
print("  ".join(analyse.extract_tags(lines2, topK=20, withWeight=False, allowPOS=())))

執行結果:

行者  八戒  師父  三藏  大聖  唐僧  沙僧  菩薩  妖精  和尚  那怪  甚麼  那裡  長老  呆子  怎麼  徒弟  不知  老孫  悟空
行者  師父  八戒  三藏  菩薩  和尚  甚麼  唐僧  妖精  怎麼  老孫  徒弟  那裡  大聖  沙僧  大王  悟空  我們  不知  不曾

注:字符集可能出現問題,自己試試 關於TF-IDF 演算法可在網上找資源

補充:

  • 關鍵詞提取所使用逆向檔案頻率(IDF)文字語料庫可以切換成自定義語料庫的路徑

用法: jieba.analyse.set_idf_path(file_name) # file_name為自定義語料庫的路徑

  • 關鍵詞提取所使用停止詞(Stop Words)文字語料庫可以切換成自定義語料庫的路徑

用法: jieba.analyse.set_stop_words(file_name) # file_name為自定義語料庫的路徑

(2)基於 TextRank 演算法的關鍵詞抽取

語法:

jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))

引數說明:同上

基本思想:

  • 將待抽取關鍵詞的文字進行分詞
  • 以固定視窗大小(預設為5,通過span屬性調整),詞之間的共現關係,構建圖
  • 計算圖中節點的PageRank,注意是無向帶權圖

例項:

import jieba.analyse as analyse
lines = open('NBA.txt', encoding='utf-8').read()
print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))
print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n'))))

lines1 = open('西遊記.txt',encoding='gb18030').read()
print("  ".join(analyse.textrank(lines1, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))

lines2 = open('西遊記語錄.txt',encoding='gb18030').read()
print("  ".join(analyse.textrank(lines2, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))

執行結果:

全明星賽  勇士  正賽  指導  對方  投籃  球員  沒有  出現  時間  威少  認為  看來  結果  相隔  助攻  現場  三連莊  介紹  嘉賓
勇士  正賽  全明星賽  指導  投籃  玩命  時間  對方  現場  結果  球員  嘉賓  時候  全隊  主持人  照片  全程  目標  快船隊  肥皂劇

行者  師父  八戒  三藏  大聖  菩薩  不知  只見  妖精  長老  國王  呆子  徒弟  卻說  悟空  小妖  不見  不能  不得  出來

師父  行者  八戒  不知  三藏  菩薩  妖精  大聖  徒弟  弟子  不得  長老  貧僧  悟空  出來  取經  國王  兄弟  不能  陛下

注: TextRank 演算法比TF-IDF 演算法的執行時間長,對於NBA.txt個人覺得TF-IDF 演算法好點,西遊記的兩個差不多

5. 詞性標註

import jieba.posseg as pseg

語法:

jieba.posseg.POSTokenizer(tokenizer=None)

新建自定義分詞器,tokenizer 引數可指定內部使用的 jieba.Tokenizer 分詞器。jieba.posseg.dt 為預設詞性標註分詞器。 標註句子分詞後每個詞的詞性,採用和 ictclas 相容的標記法。

例項:

import jieba.posseg as pseg
words = pseg.cut("我愛自然語言處理")
for word, flag in words:
    print('%s %s' % (word, flag))

執行結果:

我 r
愛 v
自然語言 l
處理 v

6. 其他

另外jieba還支援,並行分詞

原理:將目標文字按行分隔後,把各行文字分配到多個 Python 程序並行分詞,然後歸併結果,從而獲得分詞速度的可觀提升 基於 python 自帶的 multiprocessing 模組,目前暫不支援 Windows

用法:

  • jieba.enable_parallel(4) # 開啟並行分詞模式,引數為並行程序數
  • jieba.disable_parallel() # 關閉並行分詞模式

Tokenize:返回詞語在原文的起止位置

例項:

import jieba
print("這是預設模式的tokenize")
result = jieba.tokenize(u'自然語言處理非常有用')
for tk in result:
    print("%s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))

print("這是搜尋模式的tokenize")
result = jieba.tokenize(u'自然語言處理非常有用', mode='search')
for tk in result:
    print("%s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))

執行結果:

這是預設模式的tokenize
自然語言		 start: 0 		 end:4
處理		 start: 4 		 end:6
非常		 start: 6 		 end:8
有用		 start: 8 		 end:10
這是搜尋模式的tokenize
自然		 start: 0 		 end:2
語言		 start: 2 		 end:4
自然語言		 start: 0 		 end:4
處理		 start: 4 		 end:6
非常		 start: 6 		 end:8
有用		 start: 8 		 end:10

寫在最後

此部落格內容來自,jieba官方Github,連結,詳細內容見Github。