python基于隐马尔可夫模型实现中文拼音输入


Posted in Python onApril 01, 2016

在网上看到一篇关于隐马尔科夫模型的介绍,觉得简直不能再神奇,又在网上找到大神的一篇关于如何用隐马尔可夫模型实现中文拼音输入的博客,无奈大神没给可以运行的代码,只能纯手动网上找到了结巴分词的词库,根据此训练得出隐马尔科夫模型,用维特比算法实现了一个简单的拼音输入法。githuh地址:https://github.com/LiuRoy/Pinyin_Demo

原理简介隐马尔科夫模型

抄一段网上的定义:

隐马尔可夫模型 (Hidden Markov Model) 是一种统计模型,用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数,然后利用这些参数来作进一步的分析。

拼音输入法中可观察的参数就是拼音,隐含的参数就是对应的汉字。

viterbi算法

参考https://zh.wikipedia.org/wiki/维特比算法,思想是动态规划,代码比较简单就不赘述。

代码解释

model定义

代码见model/table.py文件,针对隐马尔科夫的三个概率矩阵,分别设计了三个数据表存储。这样的好处很明显,汉字的转移概率矩阵是一个非常大的稀疏矩阵,直接文件存储占用空间很大,并且加载的时候也只能一次性读入内存,不仅内存占用高而且加载速度慢。此外数据库的join操作非常方便viterbi算法中的概率计算。

数据表定义如下:

class Transition(BaseModel):

  __tablename__ = 'transition'

  id = Column(Integer, primary_key=True)
  previous = Column(String(1), nullable=False)
  behind = Column(String(1), nullable=False)
  probability = Column(Float, nullable=False)


class Emission(BaseModel):

  __tablename__ = 'emission'

  id = Column(Integer, primary_key=True)
  character = Column(String(1), nullable=False)
  pinyin = Column(String(7), nullable=False)
  probability = Column(Float, nullable=False)


class Starting(BaseModel):

  __tablename__ = 'starting'

  id = Column(Integer, primary_key=True)
  character = Column(String(1), nullable=False)
  probability = Column(Float, nullable=False)

模型生成

代码见train/main.py文件,里面的initstarting,initemission,init_transition分别对应于生成隐马尔科夫模型中的初始概率矩阵,发射概率矩阵,转移概率矩阵,并把生成的结果写入sqlite文件中。训练用到的数据集是结巴分词里的词库,因为没有训练长句子,最后运行的结果也证明只能适用于短句输入。

初始概率矩阵

统计初始化概率矩阵,就是找出所有出现在词首的汉字,并统计它们出现在词首的次数,最后根据上述数据算出这些汉字出现在词首的概率,没统计的汉字就认为出现在词首的概率是0,不写入数据库。有一点注意的是为了防止概率计算的时候因为越算越小导致计算机无法比较,所有的概率都进行了自然对数运算。统计的结果如下:

python基于隐马尔可夫模型实现中文拼音输入

转移概率矩阵

此处用到的是最简单的一阶隐马尔科夫模型,即认为在一个句子里,每个汉字的出现只和它前面的的一个汉字有关,虽然简单粗暴,但已经可以满足大部分情况。统计的过程就是找出字典中每个汉字后面出现的汉字集合,并统计概率。因为这个概率矩阵非常的大,逐条数据写入数据库过慢,后续可以优化为批量写入,提高训练效率。结果如下:

python基于隐马尔可夫模型实现中文拼音输入

上图展示的一后面出现概率最高的十个字,也挺符合日常习惯。

发射概率矩阵

通俗点就是统计每个汉字对应的拼音以及在日常情况下的使用概率,已暴举例,它有两个读音:bao和pu,难点就是找bao和pu出现的概率。此处统计用到了pypinyin模块,把字典中的短语转换为拼音后进行概率统计,但是某些地方读音也不完全正确,最后运行的输入法会出现和拼音不匹配的结果。统计结果如下:

python基于隐马尔可夫模型实现中文拼音输入

viterbi实现

代码建input_method/viterbi.py文件,此处会找到最多十个局部最优解,注意是十个局部最优解而不是十个全局最优解,但是这十个解中最优的那个是全局最优解,代码如下:

def viterbi(pinyin_list):
  """
  viterbi算法实现输入法

  Aargs:
    pinyin_list (list): 拼音列表
  """
  start_char = Emission.join_starting(pinyin_list[0])
  V = {char: prob for char, prob in start_char}

  for i in range(1, len(pinyin_list)):
    pinyin = pinyin_list[i]

    prob_map = {}
    for phrase, prob in V.iteritems():
      character = phrase[-1]
      result = Transition.join_emission(pinyin, character)
      if not result:
        continue

      state, new_prob = result
      prob_map[phrase + state] = new_prob + prob

    if prob_map:
      V = prob_map
    else:
      return V
  return V

结果展示

运行input_method/viterbi.py文件,简单的展示一下运行结果:

python基于隐马尔可夫模型实现中文拼音输入

问题统计:

统计字典生成转移矩阵写入数据库的速度太慢,运行一次要将近十分钟。发射概率矩阵数据不准确,总有一些汉字的拼音不匹配。训练集太小,实现的输入法不适用于长句子。

Python 相关文章推荐
python以环状形式组合排列图片并输出的方法
Mar 17 Python
浅谈Python中的闭包
Jul 08 Python
Python按行读取文件的简单实现方法
Jun 22 Python
对python3 urllib包与http包的使用详解
May 10 Python
Python3几个常见问题的处理方法
Feb 26 Python
Python I/O与进程的详细讲解
Mar 08 Python
Python实例方法、类方法、静态方法的区别与作用详解
Mar 25 Python
wxPython:python首选的GUI库实例分享
Oct 05 Python
python装饰器相当于函数的调用方式
Dec 27 Python
python GUI库图形界面开发之PyQt5信号与槽基础使用方法与实例
Mar 06 Python
python异常处理之try finally不报错的原因
May 18 Python
利用Python中的Xpath实现一个在线汇率转换器
Sep 09 Python
Python使用BeautifulSoup库解析HTML基本使用教程
Mar 31 #Python
Python使用Mechanize模块编写爬虫的要点解析
Mar 31 #Python
Python语言实现获取主机名根据端口杀死进程
Mar 31 #Python
Linux中Python 环境软件包安装步骤
Mar 31 #Python
Python内置的HTTP协议服务器SimpleHTTPServer使用指南
Mar 30 #Python
横向对比分析Python解析XML的四种方式
Mar 30 #Python
python简单实现刷新智联简历
Mar 30 #Python
You might like
比较全的PHP 会话(session 时间设定)使用入门代码
2008/06/05 PHP
php面向对象全攻略 (一) 面向对象基础知识
2009/09/30 PHP
PHP容易被忽略而出错陷阱 数字与字符串比较
2011/11/10 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
PHP文件操作详解
2016/12/30 PHP
php根据命令行参数生成配置文件详解
2019/03/15 PHP
setAttribute 与 class冲突解决
2008/02/17 Javascript
javascript各种复制代码收集
2008/09/20 Javascript
jquery实现页面图片等比例放大缩小功能
2014/02/12 Javascript
一张表格告诉你windows.onload()与$(document).ready()的区别
2014/05/16 Javascript
jQuery实现响应鼠标滚动的动感菜单效果
2015/09/21 Javascript
原生javascript实现分享到朋友圈功能 支持ios和android
2016/05/11 Javascript
js无提示关闭浏览器窗口的两种方法分析
2016/11/06 Javascript
jQuery实现select模糊查询(反射机制)
2017/01/14 Javascript
js实现表单项的全选、反选及删除操作示例
2020/06/05 Javascript
[03:07]【DOTA2亚洲邀请赛】我们,梦开始的地方
2017/03/07 DOTA
Python实现list反转实例汇总
2014/11/11 Python
Python输出9*9乘法表的方法
2015/05/25 Python
Python正则获取、过滤或者替换HTML标签的方法
2016/01/28 Python
python 3.6 +pyMysql 操作mysql数据库(实例讲解)
2017/12/20 Python
基于python实现聊天室程序
2018/07/27 Python
python celery分布式任务队列的使用详解
2019/07/08 Python
Django连接数据库并实现读写分离过程解析
2019/11/13 Python
Python模块的定义,模块的导入,__name__用法实例分析
2020/01/07 Python
如何使用PyCharm引入需要使用的包的方法
2020/09/22 Python
CSS3实现同时执行倾斜和旋转的动画效果
2016/10/27 HTML / CSS
详解利用css3的var()实现运行时改变scss的变量值
2021/03/02 HTML / CSS
西班牙拥有最佳品牌的动物商店:Animalear.com
2018/01/05 全球购物
德国最大的服装、鞋子和配件在线商店之一:Outfits24
2019/07/23 全球购物
电台实习生求职信
2014/02/25 职场文书
勤奋学习演讲稿
2014/05/10 职场文书
优秀团干部个人事迹
2014/05/29 职场文书
讲党性心得体会
2014/09/03 职场文书
国庆节慰问信
2015/02/15 职场文书
检察院起诉意见书
2015/05/20 职场文书
2015年秋季开学典礼校长致辞
2015/07/16 职场文书