分詞之精確模式(使用HMM維特比算法發現新詞) - CSDN博客
文章推薦指數: 80 %
py 檔則儲存了HMM的參數,從檔名可以看得出來,它們分別是HMM的初始概率、轉移概率及發射概率(皆以對數值表示),在 __init__.py 裡會被用到。
jieba/ ...
jieba源碼研讀筆記(七)-分詞之精確模式(使用HMM維特比算法發現新詞)
keineahnung2345
于 2019-02-2817:58:11 发布
797
收藏
1
分类专栏:
NLP
機器學習
jieba源碼研讀筆記
文章标签:
jieba
nlp
版权声明:本文为博主原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/keineahnung2345/article/details/86646594
版权
NLP
同时被3个专栏收录
18篇文章
0订阅
订阅专栏
機器學習
23篇文章
0订阅
订阅专栏
jieba源碼研讀筆記
18篇文章
2订阅
订阅专栏
jieba源碼研讀筆記(七)-分詞之精確模式(使用HMM維特比算法發現新詞)
前言jieba/finalseg的目錄結構jieba/finalseg/__init__.py載入HMM的參數viterbi函數__cut函數add_force_split函數cut函數
jieba/__init__.py__cut_DAG函數
參考連結
前言
jieba分詞的精確模式分為1.不使用HMM(使用動態規劃算法)或2.使用HMM(使用維特比算法發現新詞)兩種模式。
本篇介紹的是使用了HMM維特比算法的精確模式,對應的是jieba/__init__.py裡的__cut_DAG這個函數。
在__cut_DAG中,仍然是以查字典為主,但是:
对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法
__cut_DAG函數是由cut(sentence,cut_all=False,HMM=True)這個函數調用。
而它又會呼叫jieba/finalseg裡的函數,下圖是幾個相關函數之間的呼叫關係。
可以從圖中看到,jieba/__init__.py裡的__cut_DAG函數調用了finalseg/__init__.py裡的cut函數。
而finalseg/__init__.py又接著調用了同一個檔案裡的__cut函數,__cut函數又接著調用了viterbi函數。
本篇將由內而外介紹,先從jieba/finalseg裡的函數開始,最後才介紹jieba/__init__.py裡的cut。
以下在介紹維特比算法時會大量參考李航-統計機器學習的10.4節,在閱讀本篇前建議先看過該章節。
jieba/finalseg的目錄結構
首先看看jieba/finalseg的目錄結構:
jieba/finalseg:
prob_emit.p
prob_emit.py
prob_start.p
prob_start.py
prob_trans.p
prob_trans.py
__init__.py
其中__init__.py實現了維特比算法。
其它的.p檔及.py檔則儲存了HMM的參數,從檔名可以看得出來,它們分別是HMM的初始概率、轉移概率及發射概率(皆以對數值表示),在__init__.py裡會被用到。
jieba/finalseg/init.py
載入HMM的參數
這個檔案裡事先定義了一些常數:
from__future__importabsolute_import,unicode_literals
importre
importos
importsys
importpickle
from.._compatimport*
MIN_FLOAT=-3.14e100
PROB_START_P="prob_start.p"
PROB_TRANS_P="prob_trans.p"
PROB_EMIT_P="prob_emit.p"
"""
參考http://www.52nlp.cn/%E4%B8%AD%E6%96%87%E5%88%86%E8%AF%8D%E5%85%A5%E9%97%A8%E4%B9%8B%E5%AD%97%E6%A0%87%E6%B3%A8%E6%B3%954
B:begin詞的首字
M:middle詞的中間字
E:end詞的尾字
S:single單字成詞
PrevStatus表示一個狀態之前可能是哪些狀態
"""
PrevStatus={
'B':'ES',#在一個詞的首字之前,只可能是上一個詞的詞尾,或者是單字成詞
'M':'MB',#在一個詞的中間字之前,可能是當前詞的中間字,或是當前詞的首字
'S':'SE',#在單字成詞之前,可能是另外一個單字成詞,也可能是上一個詞的詞尾
'E':'BM'#在一個詞的詞尾之前,可能是詞首或是中間字
}
"""
從.p檔或.py檔載入start_P,trans_P,emit_P
"""
defload_model():
start_p=pickle.load(get_module_res("finalseg",PROB_START_P))
trans_p=pickle.load(get_module_res("finalseg",PROB_TRANS_P))
emit_p=pickle.load(get_module_res("finalseg",PROB_EMIT_P))
returnstart_p,trans_p,emit_p
ifsys.platform.startswith("java"):
start_P,trans_P,emit_P=load_model()
else:
from.prob_startimportPasstart_P
from.prob_transimportPastrans_P
from.prob_emitimportPasemit_P
來看看start_P,trans_P,emit_P這三個變數裡面是什麼:
importpprint
pprint.pprint(start_P,width=1)
"""
4個狀態的初始log機率
{'B':-0.26268660809250016,#使用e^x換算回去,機率約為0.76
'E':-3.14e+100,#0
'M':-3.14e+100,#0
'S':-1.4652633398537678}#機率約為0.23
"""
pprint.pprint(trans_P,width=1)
"""
4個狀態間的轉移log機率
{'B':{'E':-0.51082562376599,
'M':-0.916290731874155},
'E':{'B':-0.5897149736854513,
'S':-0.8085250474669937},
'M':{'E':-0.33344856811948514,
'M':-1.2603623820268226},
'S':{'B':-0.7211965654669841,
'S':-0.6658631448798212}}
"""
#發射概率
#每個狀態挑選5個字來看
pprint.pprint({k:dict(random.sample(v.items(),5))fork,vinemit_P.items()},width=1)
"""
在4個狀態,觀察到不同字的機率
{'B':{'十':-6.007344000041945,#emit_P['B']有6857個item
'囤':-12.607094089862704,
'撷':-14.695424578959786,
'柱':-9.88964863468285,
'齏':-13.868746005775318},
'E':{'僱':-12.20458319365197,#7439
'凜':-11.06728136003368,
'妪':-13.50584051208595,
'拟':-9.377654786484934,
'焘':-11.21858978309201},
'M':{'咦':-13.561365842482271,#6409
'疊':-9.63829300086754,
'荑':-15.758590419818491,
'趙':-10.120235750484746,
'骛':-12.324603215333344},
'S':{'妳':-13.847864212264698,#14519
'庝':-10.732052690793973,
'弑':-12.34762559179559,
'氜':-16.116547753583063,
'筱':-13.957063504229689}}
"""
start_P,trans_P,emit_P這三個變數代表了HMM的參數,在viterbi函數中會用到。
viterbi函數
參考李航統計機器學習中的章節10.4-預測算法。
維特比算法是在給定模型參數及觀察序列的情況下,用於求解狀態序列的算法。
注意這個函數只適用於obs(也就是觀察序列)全是漢字的情況。
defviterbi(obs,states,start_p,trans_p,emit_p):
#參考:李航-統計機器學習10.4預測算法
"""
obs:觀察序列
states:所有可能的狀態
start_p:李航書中的Pi,一開始在每個不同狀態的機率
trans_p:李航書中的A,轉移矩陣
emit_p:李航書中的B,每個狀態發射出不同觀察值的機率矩陣
"""
"""
算法10.5(1)初始化
"""
V=[{}]#tabular,李航書中的delta,表示在時刻t狀態為y的所有路徑的機率最大值,用一個字典表示一個時間點
#V如果以矩陣表示的話會是len(obs)*len(states)=T*4的大小
path={}#李航書中的psi是一個矩陣。
這裡採用不同的實現方式:使用path儲存各個狀態最有可能的路徑
foryinstates:#init
#y代表4種狀態中的一個
#在時間點0有路徑{y}的機率是為:在狀態y的初始機率乘上狀態y發射出obs[0]觀察值的機率
#因為這裡是機率對數,所以用加的
V[0][y]=start_p[y]+emit_p[y].get(obs[0],MIN_FLOAT)
path[y]=[y]#在一開始時各狀態y的最大機率路徑都只包含它自己
"""
算法10.5(2)由t=0遞推到t=1...T-1(因為index是由0開始,所以最後一個是T-1)
"""
fortinxrange(1,len(obs)):#遞推:由前一時刻的path算出當前時刻的path
V.append({})
newpath={}#基於path(時刻t-1各個狀態機率最大的路徑)得到的,代表時刻t各個狀態的機率最大的路徑
foryinstates:
#在狀態y發射觀察值obs[t]的機率對數
em_p=emit_p[y].get(obs[t],MIN_FLOAT)
"""
V[t-1][y0]+trans_p[y0].get(y,MIN_FLOAT)+em_p:
前一個時間點在y0的路徑的機率最大值*由y0轉移到y的機率*在狀態y0發射出y的機率
fory0inPrevStatus[y]:
這裡使用PrevStatus這個字典獲取狀態y前一個時間點可能在什麼狀態,而不是使用所有的狀態
max([(a1,b1),(a2,b2)]):
會先比較a1與a2,如果一樣,繼續比較b1與b2
state:
李航書中的psi_t(y):如果時刻t時在狀態y,那麼在時刻t-1時最有可能在哪一個狀態?
"""
(prob,state)=max(
[(V[t-1][y0]+trans_p[y0].get(y,MIN_FLOAT)+em_p,y0)fory0inPrevStatus[y]])
V[t][y]=prob#時刻t在狀態y的路徑的機率最大值
#時刻t狀態y機率最大的路徑為時刻t-1狀態為state機率最大的路徑加上當前狀態y
#註:path是前一時刻(時刻t-1)在各個狀態機率最大的路徑
newpath[y]=path[state]+[y]
path=newpath#時刻t各個狀態機率最大的路徑
"""
算法10.5(3)終止
"""
"""
foryin'ES':限制最後一個狀態只能是這兩個
len(obs)-1:最後一個時間點,即T-1
prob:時間T-1所有路徑的機率最大值
state:時間T-1最有可能在哪一個狀態上
"""
(prob,state)=max((V[len(obs)-1][y],y)foryin'ES')
"""
李航書中本來還有一步最優路徑回溯,
但是這裡因為path的實現方式跟書中不同,所以不必回溯。
這裡的path直接記錄了len(states)條路徑
我們只要從中選一條機率最大的即可
"""
#path[state]:終點是state的路徑
return(prob,path[state])
__cut函數
viterbi函數返回的是狀態序列及其機率值。
在__cut函數中,調用了viterbi,並依據狀態序列來切分傳入的句子。
要注意的是:__cut函數只能接受全是漢字的句子當作輸入。
所以我們等一下會看到,它還會有一個wrapper,用來處理句子中包含英數字或其它符號的情況。
def__cut(sentence):
globalemit_P#為什麼只有emit_P是global?
#向viterbi函數傳入觀察序列,可能狀態值以及三個矩陣
#得到機率最大的狀態序列及其機率
prob,pos_list=viterbi(sentence,'BMES',start_P,trans_P,emit_P)
begin,nexti=0,0
#printpos_list,sentence
#利用pos_list(即狀態序列)來切分sentence
fori,charinenumerate(sentence):
pos=pos_list[i]
ifpos=='B':
begin=i
elifpos=='E':
yieldsentence[begin:i+1]
nexti=i+1
elifpos=='S':
yieldchar
nexti=i+1
"""
如果sentence[-1]是'E'或'S',那麼句中的最後一個詞就會被yield出來,而nexti就派不上用場
如果sentence[-1]是'B'或'M',那麼在迴圈中就不會yield出最後一個詞,
所以到迴圈外後我們需要nexti(表示上個詞詞尾的下一個字的位置),然後用yield來產生句中的最後一個詞
"""
ifnexti
__cut_DAG函數則是在finalseg.cut外又包了一層,以查字典為主,維特比分詞為輔。
对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法
def__cut_DAG(self,sentence):
DAG=self.get_DAG(sentence)
route={}
self.calc(sentence,DAG,route)
x=0
buf=''
N=len(sentence)
whilex
谢谢!
1算法简介
在结巴分词2--基于前缀词典及动态规划实现分词博文中,博主已经介绍了基于前缀词典和动态规划方法实现分词,但是如果没有前缀词典或者有些词不在前缀词典中,jieba分词一样可以分词,那么jieba分词是如何对未登录词进行分词呢?这就是本文将要讲解的,基...
python中文分词(规则分词实现,HMM+Viterbi实现统计分词,jieba分词应用)
沃·夏澈德的博客
11-05
3568
参考书目:python自然语言处理实战——核心技术与算法
规则分词
顾名思义,直接靠规则来进行分词,这种方法是一种机械的分词方法,主要手段就是通过将语句的每个字符串与词表进行匹配,找到就分,找不到就不分。
词表:
天气
真好
今天
伤心
冬瓜汤
句子:
今天天气真好
结果:
今天/天气/真好
按照匹配的方式,规则分词主要有正向最大匹配法,逆向最大匹配法以及双向最大匹配...
[工具]python中文分词---【jieba】
码上的生活
03-23
8472
jieba“结巴”中文分词:做最好的Python中文分词组件“Jieba”(Chinesefor“tostutter”)Chinesetextsegmentation:builttobethebestPythonChinesewordsegmentationmodule.
ScrolldownforEnglishdocumentation.
特点
支持三
中文分词的基本原理以及jieba分词的用法
热门推荐
JohnSon
01-21
6万+
结巴分词是国内程序员用Python开发的一个中文分词模块,可能是最好的Python中文分词组件?
中文分词的原理
–
1、中文分词(ChineseWordSegmentation)指的是将一个汉字序列切分成一个一个单独的词。
分词就是将连续的字序列按照一定的规范重新组合成词序列的过程
2、现有的分词算法可分为三大类:基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法
【转】中文分词-结巴jieba手册
清风不识字12138的博客
11-29
4091
jieba“结巴”中文分词:做最好的Python中文分词组件“Jieba”(Chinesefor“tostutter”)Chinesetextsegmentation:builttobethebestPythonChinesewordsegmentationmodule.ScrolldownforEnglishdocumentation.特点支持三种分词
jieba中文处理
芦金宇的专栏
10-31
1万+
和拉丁语系不同,亚洲语言是不用空格分开每个有意义的词的。
而当我们进行自然语言处理的时候,大部分情况下,词汇是我们对句子和文章理解的基础,因此需要一个工具去把完整的文本中分解成粒度更细的词。
jieba就是这样一个非常好用的中文工具,是以分词起家的,但是功能比分词要强大很多。
jieba源碼研讀筆記(二)-Python2/3相容
keineahnung2345的博客
02-20
255
jieba的主程序是__init__.py,定義了cut,cut_for_search等用於分詞的函數。
在正式介紹分詞函數以前,先來看看_compat.py這個檔案,它用於處理Python2/3之間相容的問題。
這個檔案中定義了get_module_res,strdecode,resolve_filename等讀檔時會用到的函數,它們會在__init__.py中頻繁地被調用。
pythonjieba分词(结巴分词)、提取词,加载词,修改词频,定义词库-转载
weixin_34357928的博客
01-24
629
转载请注明出处
“结巴”中文分词:做最好的Python中文分词组件,分词模块jieba,它是python比较好用的分词模块,支持中文简体,繁体分词,还支持自定义词库。
jieba的分词,提取关键词,自定义词语。
结巴分词的原理原文链接:http://blog.csdn.net/HHTNAN/article/details/78722754
1、jieba.cut分词三种模式
...
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
©️2022CSDN
皮肤主题:像素格子
设计师:CSDN官方博客
返回首页
keineahnung2345
CSDN认证博客专家
CSDN认证企业博客
码龄4年
暂无认证
233
原创
8万+
周排名
2万+
总排名
27万+
访问
等级
4403
积分
55
粉丝
94
获赞
66
评论
209
收藏
私信
关注
热门文章
docker-composeup:ERROR:Encounterederrorswhilebringinguptheproject.錯誤及解決方式
38195
Errorresponsefromdaemon:Dockerfileparseerrorlinexxx:unknowninstruction:xxx
33764
PIL及matplotlib:OSError:cannotidentifyimagefile錯誤及解決方式
15153
CannotconnecttotheDockerdaemonatunix:///var/run/docker.sock.Isthedockerdaemonrunning?錯誤
10506
Ubuntu下安裝Python版OpenCV
7305
分类专栏
Redmine
8篇
三維點雲
50篇
線性代數
12篇
三維重建
5篇
TensorRT源碼研讀筆記
22篇
jieba源碼研讀筆記
18篇
matterport/Mask_RCNN代碼研讀筆記
2篇
CV
8篇
深度學習
13篇
Linux
45篇
Tensorflow踩坑實錄
5篇
Python學習筆記
13篇
macOS
4篇
機器學習
23篇
docker
18篇
Spark
9篇
大數據
9篇
ftp
2篇
Stackoverflow
1篇
NLP
18篇
Darknet
Windows
2篇
PyTorch
1篇
C++
50篇
C語言
13篇
最新评论
KITTIdepthcompletion數據集評測
nk北夏:
老哥请问一下,深度估计用的GT是经过处理的还是lidardepth?
Errorresponsefromdaemon:Dockerfileparseerrorlinexxx:unknowninstruction:xxx
喵先生丶:
台湾的吧
PCL-MLS代碼研讀(十四)-DISTINCT_CLOUD上採樣方法
keineahnung2345:
我把代碼放在https://gist.github.com/keineahnung2345/f3f323e4c643770036fcdf59a648e007,可以參考看看
PCL-MLS代碼研讀(十四)-DISTINCT_CLOUD上採樣方法
Dawdler416:
请问博主,您使用的曲面模型是怎么生成的啊,可以指点一下吗
PCLMLS論文ComputingandRenderingPointSetSurfaces研讀筆記
keineahnung2345:
太謝謝你了,我原文分成一到三步確實有點問題
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
redmine插件安裝及卸載
Generalized-ICP(GICP)論文研讀
兩獨立高斯隨機變數之和
2022年7篇
2021年76篇
2020年79篇
2019年27篇
2018年47篇
目录
目录
分类专栏
Redmine
8篇
三維點雲
50篇
線性代數
12篇
三維重建
5篇
TensorRT源碼研讀筆記
22篇
jieba源碼研讀筆記
18篇
matterport/Mask_RCNN代碼研讀筆記
2篇
CV
8篇
深度學習
13篇
Linux
45篇
Tensorflow踩坑實錄
5篇
Python學習筆記
13篇
macOS
4篇
機器學習
23篇
docker
18篇
Spark
9篇
大數據
9篇
ftp
2篇
Stackoverflow
1篇
NLP
18篇
Darknet
Windows
2篇
PyTorch
1篇
C++
50篇
C語言
13篇
目录
打赏作者
keineahnung2345
你的鼓励将是我创作的最大动力
¥2
¥4
¥6
¥10
¥20
输入1-500的整数
余额支付
(余额:--)
扫码支付
扫码支付:¥2
获取中
扫码支付
您的余额不足,请更换扫码支付或充值
打赏作者
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
0
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
余额充值
延伸文章資訊
- 1如何使用jieba 結巴中文分詞程式(Example) - Coderwall
A protip by fukuball about python and jieba. ... 對於辨識新詞(字典詞庫中不存在的詞)則使用了HMM 模型(Hidden Markov Model...
- 2jieba结巴分词原理浅析与理解HMM应用在中文分词及部分代码 ...
背景. 这篇博客主要阐述我们在分词任务中常用的分词库结巴jieba分词的实现原理,以及之前博客中讲到的HMM在分词中的应用,算是复习与加深理解一下HMM ...
- 3分詞之精確模式(使用HMM維特比算法發現新詞) - CSDN博客
py 檔則儲存了HMM的參數,從檔名可以看得出來,它們分別是HMM的初始概率、轉移概率及發射概率(皆以對數值表示),在 __init__.py 裡會被用到。 jieba/ ...
- 4fxsjy/jieba: 结巴中文分词
注意:自动计算的词频在使用HMM 新词发现功能时可能无效。 代码示例:. >>> print('/'.join(jieba.cut ...
- 5(八)通俗易懂理解——jieba中的HMM中文分词原理 - 知乎专栏
jieba是基于统计的分词方法,jieba分词采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合,对于未登录词,采用了基于汉字成词能力的HMM模型, ...