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分割文件的常用方法
Nov 01 Python
Python中使用Flask、MongoDB搭建简易图片服务器
Feb 04 Python
python将MongoDB里的ObjectId转换为时间戳的方法
Mar 13 Python
Python中方法链的使用方法
Feb 23 Python
Python之文字转图片方法
May 10 Python
Python切片索引用法示例
May 15 Python
[原创]Python入门教程1. 基本运算【四则运算、变量、math模块等】
Oct 28 Python
python内存管理机制原理详解
Aug 12 Python
Python流程控制 if else实现解析
Sep 02 Python
使用Python文件读写,自定义分隔符(custom delimiter)
Jul 05 Python
浅谈Python里面None True False之间的区别
Jul 09 Python
python 基于selenium实现鼠标拖拽功能
Dec 24 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 字符过滤类,用于过滤各类用户输入的数据
2009/05/27 PHP
php如何调用webservice应用介绍
2012/11/24 PHP
PHP统计目录大小的自定义函数分享
2014/11/18 PHP
laravel解决迁移文件一次删除创建字段报错的问题
2019/10/24 PHP
2020最新版 PhpStudy V8.1版本下载安装使用详解
2020/10/30 PHP
用javascript实现改变TEXTAREA滚动条和按钮的颜色,以及怎样让滚动条变得扁平
2007/04/20 Javascript
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
2007/05/07 Javascript
JavaScript入门教程(8) Location地址对象
2009/01/31 Javascript
JavaScript CSS修改学习第一章 查找位置
2010/02/19 Javascript
jquery构造器的实现代码小结
2011/05/16 Javascript
js模拟C#中List的简单实例
2014/03/06 Javascript
JS中判断JSON数据是否存在某字段的方法
2014/03/07 Javascript
javascript控制图片播放的实现代码
2020/07/29 Javascript
fastclick插件导致日期(input[type="date"])控件无法被触发该如何解决
2015/11/09 Javascript
基于html5和nodejs相结合实现websocket即使通讯
2015/11/19 NodeJs
在ASP.NET MVC项目中使用RequireJS库的用法示例
2016/02/15 Javascript
Vue.js如何优雅的进行form validation
2017/04/07 Javascript
angular2 组件之间通过service互相传递的实例
2018/09/30 Javascript
使用微信小程序开发弹出框应用实例详解
2018/10/18 Javascript
jQuery 判断元素是否存在然后按需加载内容的实现代码
2020/01/16 jQuery
Python多线程爬虫实战_爬取糗事百科段子的实例
2017/12/15 Python
Python实现获取前100组勾股数的方法示例
2018/05/04 Python
Python自定义函数实现求两个数最大公约数、最小公倍数示例
2018/05/21 Python
Python中pandas模块DataFrame创建方法示例
2018/06/20 Python
Python集中化管理平台Ansible介绍与YAML简介
2019/06/12 Python
python GUI库图形界面开发之PyQt5信号与槽机制、自定义信号基础介绍
2020/02/25 Python
VS2019+python3.7+opencv4.1+tensorflow1.13配置详解
2020/04/16 Python
CSS3 网页下拉菜单代码解释 中文翻译
2010/02/27 HTML / CSS
HTML5的标签的代码的简单介绍 HTML5标签的简介
2012/05/28 HTML / CSS
介绍JAVA 中的Collection FrameWork(及如何写自己的数据结构)
2014/10/31 面试题
工地标语大全
2014/06/18 职场文书
企业办公室主任岗位职责
2015/04/01 职场文书
工作表现证明
2015/06/15 职场文书
2015年小学总务工作总结
2015/07/21 职场文书
2015年三好一满意工作总结
2015/07/24 职场文书
vue3中的组件间通信
2021/03/31 Vue.js