jieba分詞的功能和性能分析


jieba分詞問題導引

  1. 用戶詞典大小最大可以有多大

  2. 用戶詞典大小對速度的影響

  3. 有相同前綴和后綴的詞匯如何區分

  4. 對比百度分詞的API

問題一:詞典大小

從源碼大小分析,整個jieba分詞的源碼總容量為81MB,其中系統詞典dict.txt的大小為5.16MB,所以用戶詞典至少可以大於5.16MB,在從詞典中的詞語數量來看,系統詞典的總的詞語數共349047行,每一行包括詞語、詞頻、詞性三個屬性,所以初步可以判斷用戶詞典可以很大。

import pandas as pd
import numpy as np
import os
path = os.getcwd()
print(path)
dict_path = os.path.join(path, 'medical_dict')
#調用pandas的read_csv()方法時,默認使用C engine作為parser engine,而當文件名中含有中文的時候,用C engine在部分情況下就會出錯。所以在調用read_csv()方法時指定engine為Python就可以解決問題了。
res = pd.read_csv(dict_path+'\\部位.txt',sep=' ',header=None,encoding='utf-8',engine='python')
res = res.append( pd.read_csv(dict_path+'\\疾病.txt',sep=' ',header=None,encoding='utf-8',engine='python') )
res = res.append( pd.read_csv(dict_path+'\\檢查.txt',sep=' ',header=None,encoding='utf-8',engine='python') )
res = res.append( pd.read_csv(dict_path+'\\手術.txt',sep=' ',header=None,encoding='utf-8',engine='python') )
res = res.append( pd.read_csv(dict_path+'\\葯品.txt',sep=' ',header=None,encoding='utf-8',engine='python') )
res = res.append( pd.read_csv(dict_path+'\\症狀.txt',sep=' ',header=None,encoding='utf-8',engine='python') )
res = res.append( pd.read_csv(dict_path+'\\中葯.txt',sep=' ',header=None,encoding='utf-8',engine='python') )
​
print(res.count())
0 35885
1 35880
2 35880

將35885個醫療詞典放入,遠比系統詞典小。之后導出為一個用戶詞典,代碼如下:

res[2] = res[1]
res[1] = 883635
print(res.head())
res.to_csv(dict_path+'\\medicaldict.txt',sep=' ',header=False,index=False)

測試語句

#encoding=utf-8
import jieba
import jieba.posseg as pseg
import os
path = os.getcwd()
# 添加用戶詞典
jieba.load_userdict(path + "\\medical_dict\\medicaldict.txt")
print( path + "\\medical_dict\\medicaldict.txt" )
test_sent = (
"患者1月前無明顯誘因及前驅症狀下出現腹瀉,起初稀便,后為水樣便,無惡心嘔吐,每日2-3次,無嘔血,無腹痛,無畏寒寒戰,無低熱盜汗,無心悸心慌,無大汗淋漓,否認里急后重感,否認蛋花樣大便,當時未重視,未就診。")
words = jieba.cut(test_sent)
print('/'.join(words))
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\Public\Documents\Wondershare\CreatorTemp\jieba.cache
Loading model cost 0.921 seconds.
Prefix dict has been built succesfully.
D:\code\jiebafenci\jieba\medical_dict\medicaldict.txt
患者/1/月前/無/明顯/誘因/及/前驅/症狀/下/出現/腹瀉/,/起初/稀便/,/后/為/水樣便/,/無/惡心/嘔吐/,/每日/2/-/3/次/,/無/嘔血/,/無/腹痛/,/無/畏寒/
寒戰/,/無/低熱/盜汗/,/無/心悸/心慌/,/無/大汗淋漓/,/否認/里急后重/感/,/否認/蛋/花樣/大便/,/當時/未/重視/,/未/就診/。

結果正常,判別一條症狀的響應速度快,jieba分詞是足以將所有的醫療詞匯放入,對於性能的影響可以在進一步分析。

問題二:詞典大小對效率的影響

  1. 35885個詞語,1條測試語句

load time: 1.0382411479949951s
cut time: 0.0s
  1. 71770個詞語,1條測試語句

load time: 1.4251623153686523s
cut time: 0.0s
  1. 1148160個詞語

load time: 7.892921209335327s
cut time: 0.0s

逐漸變慢了

  1. 2296320個詞語

load time: 15.106632471084595s
cut time: 0.0s

在本機已經開始變得很慢了

  1. 4592640個詞語

load time: 30.660043001174927s
cut time: 0.0s
  1. 9185280個詞語

load time: 56.30760192871094s
  1. 18370560個詞語

load time: 116.30s

制作為折線圖如上,基本上詞語大小和加載速度呈正比。但是加載的詞典一般保留在內存中,對內存和I/O負擔較大。

之后將2220條病史數據導入后,對分詞處理時間依然沒有什么影響,在0.1s以內,分詞時間可以忽略。

問題三:有相同前綴和后綴的詞匯如何區分

  1. 關於無尿急、尿頻、尿痛,在jieba分詞導入用戶詞典后是能正確區分的,相關病例如下

/患者/3/小時/前/無/明顯/誘因/出現/上/腹部/疼痛/,/左/上腹/為主/,/持續性/隱痛/,/無/放射/,/無/惡心/及/嘔吐/,/無/泛酸/及/噯氣/,/無/腹脹/及/腹瀉/,/無/咳嗽/及/咳痰/,/無/胸悶/及/氣急/,/無/腰酸/及/腰疼/,/無/尿急/、/尿頻/及/尿痛/,/無/頭暈/,/無/黒/曚/,/無/畏寒/及/發熱/,/無尿/黃/,/無/口苦/,/來/我院/求治/。

但是無尿黃划分成了無尿/黃,在查找用戶詞典后,發現是詞典中沒有尿黃的症狀,為詞典問題,便跳過處理。但是在症狀中確實同時存在無尿和尿頻,初步分析可能是詞語在詞典中的順序,或者是jieba分詞系統內部的分詞策列導致,現在分析第一種可能,在詞典中無尿在14221行,尿頻在13561行,現在將無尿放在第一行,看分詞結果。結果仍然為無/尿頻,所以結果為是jieba分詞內部的算法策略,當兩個詞語的詞頻相同是,后匹配的詞語優先,比如在詞語匹配中尿頻比無尿后匹配,所以最后區分尿頻,這與正確的分法也相匹配。

  1. 再比如腰部酸痛,在部位中有腰部這個詞語,在症狀中也有腰部酸痛這個詞語,測試jieba分詞會如何區分

測試詞典:
腰部 883635
酸痛 883635
腰部酸痛 883635
測試結果:
腰部酸痛

將詞典順序交換后,並將腰部和疼痛的詞頻都設置成大於883635的值后,結果仍然是腰部酸痛,所以可以得出jieba分詞更傾向於分長度更長的詞語,即使短的詞語的詞頻較大也會優先分長度更長的。而我去向自己學醫的同學了解后,他也認為分成長詞更合理,所以也不用處理。

  1. 在查看病例中,發現很多病例中存在方位名 + 部位名的詞語,並且應該分成一個詞語,如下代碼實現添加方位名+部位名的詞典,如詞典中已經存在,便跳過。

res = pd.read_csv(dict_path+'\\部位.txt',sep=' ',header=None,encoding='utf-8',engine='python')
direct = ['','','','','','']
print(res[0].head())
resum = res[0].count()
print(resum)
result = res[0]
# 在部位名前加上方位名
for item in res[0].tolist():
if(item[0] in direct):
continue
else:
temp = Series(['' + item, '' + item], index = [resum+1,resum+2])
resum = resum + 2
result = result.append(temp)
print(result.tail())
df = pd.DataFrame(result)
print(df.describe())

 

百度分詞

github地址 : https://github.com/baidu/lac/

實現代碼

from LAC import LAC
​
# 裝載分詞模型
lac = LAC(mode='seg')
​
# 單個樣本輸入,輸入為Unicode編碼的字符串
text = u"LAC是個優秀的分詞工具"
seg_result = lac.run(text)
​
# 批量樣本輸入, 輸入為多個句子組成的list,平均速率會更快
texts = [u"腰部酸痛"]
lac.load_customization('userdict.txt', sep=None)
seg_result = lac.run(texts)
print(seg_result)

用戶詞典只需要添加詞語和詞性即可。經過測試得到結論:

1.百度分詞無詞頻的概念,但是也更傾向於分長度更長的詞語。

  1. 后匹配的詞語優先,如無尿頻,也會划分成無/尿頻,與詞典中的順序無關。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM