分詞之精確模式(使用HMM維特比算法發現新詞) - CSDN博客

文章推薦指數: 80 %
投票人數:10人

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>>re_han.split(sentence) ['Andy','今年','13','歲了',''] 測試jieba.finalseg.cut: blkre_han.match(blk)list(__cut(blk))re_skip.split(blk)yield出的分詞結果‘Andy’None[’’,‘Andy’,‘’]‘Andy’‘今年’<_sre.sre_matchobject>[‘今年’]‘今年’‘13’None[’’,‘13’,‘’]‘13’‘歲了’<_sre.sre_matchobject>[‘歲’,‘了’]‘歲’,‘了’‘’None[’’] jieba/init.py Tokenizer類別裡的__cut_DAG函數: __cut_DAG函數 finalseg.cut函數不查找字典,而是只依靠HMM維特比算法來分詞。

__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 结婚/的/和/尚未/结婚/的 结婚/的/和尚/未/结婚/的 未登录词问题 有两种解释:一是已有的词表中没有收录的词,二是已有的训练语料 jieba库:Tokenizer()类详解:(三)词典增删词 最新发布 qq_51945755的博客 11-09 975 2021SC@SDUSC 源码: defadd_word(self,word,freq=None,tag=None): """ Addawordtodictionary. freqandtagcanbeomitted,freqdefaultstobeacalculatedvalue thatensuresthewordcanbecutout. """ python结巴分词(jieba)详解 lukabruce的博客 09-03 1万+ 【转自:https://www.cnblogs.com/jackchen-Net/p/8207009.html】 “结巴”中文分词:做最好的Python中文分词组件 "Jieba"(Chinesefor"tostutter")Chinesetextsegmentation:builttobethebestPythonChinesewordsegmentati... 结巴分词3--基于汉字成词能力的HMM模型识别未登录词 weixin_34037977的博客 11-23 225 作者:zhbzz2007出处:http://www.cnblogs.com/zhbzz2007欢迎转载,也请保留这段声明。

谢谢! 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币套餐、付费专栏及课程。

余额充值



請為這篇文章評分?