zoukankan      html  css  js  c++  java
  • 利用隐马尔科夫链(HMM)模型实现中文分词

    1.什么是HMM?

    隐马尔科夫链(HMM)是一个五元组:

    • 隐状态集合 ;
    • 观测状态集合;
    • 状态概率转移矩阵;
    • 观察状态概率矩阵;
    • 初始状态概率分布;

    2.HMM有两个假设:

    • 齐次马尔可夫链假设:任意时刻的隐藏状态只依赖与前一时刻的隐藏状态。
    • 观测独立性假设:任意时刻的观察状态,只依赖与当前时刻的隐藏状态。

    3.HMM可以解决3类基本问题:

    • 评估观察序列的概率。
    • 学习模型参数。即给定观察序列,估计模型的参数,是观察序列出现的概率最大。
    • 预测问题。即给定观察序列和模型,求最有可能出现的对应状态序列。

    4.中文分词

    <1>抽象出五元组

    • StatusSet。状态集合为{B, M, E, S}.其中B表示词首,M表示词中间,E表示词尾,S表示单字成词。
    • ObservedSet。观察状态集合就是所有的汉字,甚至包括标点符号组成的集合。
    • TransProbMatrix。状态转移概率矩阵,就是{B, M, E, S} X {B, M, E, S}的一个4X4矩阵。
    • EmitProbMatrix。观察矩阵的每个元素都是一个条件概率,代表P(Observed[i]|Status[j])。
    • InitStatus。初始状态概率分布表示句子的第一个字属于{B,E,M,S}这四种状态的概率。

    <2>模型训练

    A_dic = {}        #状态转移概率矩阵
    B_dic = {} #观察概率矩阵
    Count_dic = {} #记录每一个状态出现的次数
    Pi_dic = {} #记录了每一行第一个状态出现的次数
    word_set = set() #存放所有出现的字(包括数字,标点符号等)
    state_list = ['B','M','E','S']
    line_num #记录样本行数


    按行遍历训练样本:

    (1) 获取每行样本对应的字符列表 word_list 以及状态列表  line_state;

    (2)记录字符集合 word_set 以及行数 line_num;

    (3)记录每行第一个状态出现的次数 Pi_dic[line_state[0]]+=1;

    (4)记录第 i-1 到 第 i 个状态转移的次数 A_dic[line_state[i-1]][line_state[i]]+=1;

    (5)记录每个状态出现的次数 count_dic[line_state[i]]+=1;

    (6)记录每个状态对应的发射概率 B_dic[line_state[i]][word_list[i]]+=1;

    (7)统计概率

        Pi_dic[state] = pi_dic[state] / line_num

        A_dic[state1][state2] = A_dic[state1][state2] / count_dic[state1]

        B_dic[state][word]  = B_dic[state][word] / count_dic[state]

    <3>利用Viterbi算法进行分词

     1 #obs:待分词的字符串
     2 #states:状态列表('B','M','E','S')
     3 #start_p:初始概率分布
     4 #trans_p:转移概率矩阵
     5 #emit_p: 发射概率矩阵
     6 def viterbi(obs, states, start_p, trans_p, emit_p):  #维特比算法
     7     V = [{}]#每个字对应一个字典,构成一个字典列表。字典格式:{‘B’:val,'M':val,'E':val,'S':val},val表示概率。字典表示当前字符对应的状态概率
     8     path = {}#以状态y结尾的路径如:{‘B’:['S','B'],'M':['B','M'],'E':['B','E'],'S':['S','S']}
     9     for y in states:   #字符串的第0个位置。初始值
    10         V[0][y] = start_p[y] * emit_p[y].get(obs[0],0)   #初始概率*发射概率。在位置0,以y状态为末尾的状态序列的最大概率
    11         path[y] = [y]#
    12     for t in range(1,len(obs)):#遍历字符串后面的字符
    13         V.append({})
    14         newpath = {}
    15         for y in states:      #从y0 -> y状态的递归,y表示当前时刻的状态,y0表示前一个时刻的状态。
    16             #prob对应状态的最大概率,state对应最大概率下上一时刻的状态。
    17             #(prob, state) = max([(V[t-1][y0] * trans_p[y0].get(y,0) * emit_p[y].get(obs[t],0) ,y0) for y0 in states if V[t-1][y0]>0])
    18             (prob, state) = max([(V[t-1][y0] * trans_p[y0].get(y,0) * emit_p[y].get(obs[t],0) ,y0) for y0 in states])
    19 
    20             V[t][y] =prob
    21             newpath[y] = path[state] + [y]#以状态y结尾的路径如:{‘B’:['S','B'],'M':['B','M'],'E':['B','E'],'S':['S','S']}
    22         path = newpath  #记录状态序列
    23     (prob, state) = max([(V[len(obs) - 1][y], y) for y in states])  #在最后一个位置,以y状态为末尾的状态序列的最大概率
    24     return (prob, path[state])  #返回概率和状态序列
    View Code
  • 相关阅读:
    使用 yo 命令行向导给 SAP UI5 应用添加一个新的视图
    SAP Fiori Elements 应用的 manifest.json 文件运行时如何被解析的
    SAP UI5 标准应用的多语言支持
    微软 Excel 365 里如何设置下拉菜单和自动高亮成指定颜色
    SAP Fiori Elements 应用里的 Title 显示的内容是从哪里来的
    本地开发好的 SAP Fiori Elements 应用,如何部署到 ABAP 服务器上?
    如何在 Cypress 测试代码中屏蔽(Suppress)来自应用代码报出的错误消息
    教你一招:让集群慢节点无处可藏
    应用架构步入“无服务器”时代 Serverless技术迎来新发展
    MySQL数据库事务隔离性的实现
  • 原文地址:https://www.cnblogs.com/cainiao-xf/p/8366402.html
Copyright © 2011-2022 走看看