这段时间了解了隐马尔科夫算法,然后拼音输入法的核心就是HMM,然后从github上找了一个输入法实现的代码来更透彻的理解算法,本文代码来源:https://github.com/LiuRoy/Pinyin_Demo,如果侵权,请联系我删除!!!

一、 拼音输入法的原理概述

1.主要原理

动态规划,用的是维特比算法实现的

2. 模型

3.  算法原理

Y1,...,Yn为输入的拼音串,Wi1,Wi2,Win是第i个音Yi的候选汉字(用Wi代表第i个拼音的候选汉字),如上图所示,将候选字连接起来可以组成很多很多的句子,每个句子都有一条路径一一对应,拼音输入法就是要根据上下文在给定的拼音条件下找到一个最优的句子,即,对应到上图中就是寻找从起点到终点的一条最短距离:

利用隐马尔科夫模型简化之得到:

定义距离:D(Wi-1,Wi)=-logP(Wi|Wi-1)*P(Yi|Wi),以此作为两个节点间的距离计算公式,利用有限状态机和动态规划进行求解

二、代码解析

1.模型训练

该代码使用sqlite数据库来保存模型参数,参数主要有初始概率、转移概率和发射概率,主要是数据库的一些知识:

1.1 定义数据表 (hmm_tables.py)

import osfrom sqlalchemy import Column, String, Integer, Float, create_engine, desc
from sqlalchemy.orm import sessionmakerfrom pinyin.model.common import current_dir, BaseModeldb_name = os.path.join(current_dir, 'hmm.sqlite')
engine = create_engine('sqlite:///{}'.format(db_name))
HMMSession = sessionmaker(bind=engine)#定义转移概率表,并定义两个类方法,一个是添加转移概率记录,一个是查询转移概率表+发射概率表的连接表
# 查询的过程有两个表的连接过程,将转移表的后一个汉字和发射表的汉字作为键,连接在一起
#由于概率取了lg,概率相乘等于lg形式的概率相加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)@classmethoddef add(cls, previous, behind, probability):"""添加转移记录Args:previous (string): 前面的汉字behind (string): 后面的汉字probability (float): 转移概率"""session = HMMSession()record = cls(previous=previous, behind=behind, probability=probability)session.add(record)session.commit()return record@classmethoddef join_emission(cls, pinyin, character):"""join emission表查询Args:pinyin (string): 拼音characters (string): 上次的汉字"""session = HMMSession()query = session.query(cls.behind,Emission.probability + cls.probability).\join(Emission, Emission.character == cls.behind).\filter(cls.previous == character).\filter(Emission.pinyin == pinyin).\order_by(desc(Emission.probability + cls.probability))result = query.first()session.commit()return result#定义发射概率表并定义两个类方法,一个是添加发射概率记录,一个是查询发射概率表+初始概率表的连接表
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)@classmethoddef add(cls, character, pinyin, probability):"""添加转移记录Args:character (string): 汉字pinyin (string): 拼音probability (float): 概率"""session = HMMSession()record = cls(character=character, pinyin=pinyin, probability=probability)session.add(record)session.commit()return record@classmethoddef join_starting(cls, pinyin, limit=10):"""join starting表查询Args:pinyin (string): 拼音limit (int): 数据个数"""session = HMMSession()query = session.query(cls.character,cls.probability + Starting.probability).\join(Starting, cls.character == Starting.character).\filter(cls.pinyin == pinyin).\order_by(desc(cls.probability + Starting.probability)).\limit(limit)result = query.all()session.commit()return result#定义初始概率表并定义一个类方法,一个是添加初始概率记录
class Starting(BaseModel):__tablename__ = 'starting'id = Column(Integer, primary_key=True)character = Column(String(1), nullable=False)probability = Column(Float, nullable=False)@classmethoddef add(cls, character, probability):"""添加转移记录Args:character (string): 汉字probability (float): 起始概率"""session = HMMSession()record = cls(character=character, probability=probability)session.add(record)session.commit()return record
2. 训练模型,添加数据表的数据 (hmm/train.py),这些概率数据都是根据dict.txt字典作为语料计算获取的
def init_start():"""计算字典中所有词的首字的集合中每个元素的概率,以此作为初始状态概率初始化起始概率 p(phrase)= freq_map[phrase[0]]/total_count"""freq_map = {}total_count = 0for phrase, frequency in iter_dict():total_count += frequency#freq_map.get(phrase[0], 0),返回freq_map[phrase[0]],若不存在,则返回默认值0freq_map[phrase[0]] = freq_map.get(phrase[0], 0) + frequencyfor character, frequency in freq_map.items():Starting.add(character, log(frequency / total_count))def init_emission():"""初始化发射概率,计算所有词的对应的拼音的概率"""character_pinyin_map = {}for phrase, frequency in iter_dict():pinyins = pinyin(phrase, style=NORMAL)for character, py in zip(phrase, pinyins):character_pinyin_count = len(py)if character not in character_pinyin_map:character_pinyin_map[character] = \{x: frequency/character_pinyin_count for x in py}else:pinyin_freq_map = character_pinyin_map[character]for x in py:pinyin_freq_map[x] = pinyin_freq_map.get(x, 0) + \frequency/character_pinyin_countfor character, pinyin_map in character_pinyin_map.items():sum_frequency = sum(pinyin_map.values())for py, frequency in pinyin_map.items():Emission.add(character, py, log(frequency/sum_frequency))def init_transition():"""初始化转移概率"""transition_map = {}for phrase, frequency in iter_dict():for i in range(len(phrase) - 1):if phrase[i] in transition_map:transition_map[phrase[i]][phrase[i+1]] = \transition_map[phrase[i]].get(phrase[i+1], 0) + frequencyelse:transition_map[phrase[i]] = {phrase[i+1]: frequency}for previous, behind_map in transition_map.items():sum_frequency = sum(behind_map.values())for behind, freq in behind_map.items():Transition.add(previous, behind, log(freq / sum_frequency))

3. 维特比算法(hmm/viterbi.py)

def viterbi(pinyin_list):"""viterbi算法实现输入法Args: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.items():character = phrase[-1]result = Transition.join_emission(pinyin, character)if not result:continuestate, new_prob = resultprob_map[phrase + state] = new_prob + probif prob_map:V = prob_mapelse:return Vreturn Vif __name__ == '__main__':while 1:string = raw_input('input:')pinyin_list = string.split()V = viterbi(pinyin_list)for phrase, prob in sorted(V.items(), key=lambda d: d[1], reverse=True):print phrase, prob

三、代码待改进的地方

  1. 统计字典生成转移矩阵写入数据库的速度太慢,运行一次要将近十分钟。
  2. 发射概率矩阵数据不准确,总有一些汉字的拼音不匹配。
  3. 训练集太小,不存在于数据表中的拼音直接没结果,且不适合长句子
  4. 拼音必须全拼,且字与字之间的拼音必须空格分开

隐马尔科夫算法之实现简易版的拼音输入法代码详解相关推荐

  1. 视频教程-隐马尔科夫算法:中文分词神器-深度学习

    隐马尔科夫算法:中文分词神器 在中国知网从事自然语言处理和知识图谱的开发,并负责带领团队完成项目,对深度学习和机器学习算法有深入研究. 吕强 ¥49.00 立即订阅 扫码下载「CSDN程序员学院APP ...

  2. 隐马尔科夫模型之Baum-Wech算法

    隐马尔科夫模型之Baum-Wech算法 https://blog.csdn.net/u014688145/article/details/53046765 Baum-Wech算法之EM算法 https ...

  3. 隐马尔科夫模型-前向算法

    转载自  隐马尔科夫模型-前向算法 隐马尔科夫模型-前向算法 在该篇文章中讲了隐马尔科夫模型(HMM)一基本模型与三个基本问题 隐马尔科夫模型-基本模型与三个基本问题,这篇文章总结一下隐马尔科夫链(H ...

  4. 隐马尔科夫模型C#语言算法实现

    开发工具: Visual Studio v2010 .NET Framework 4 Client Profile 版本历史: V1.1 2011年06月09日 修正UMDHMM在Baum-Welch ...

  5. 【深度】从朴素贝叶斯到维特比算法:详解隐马尔科夫模型

    详解隐马尔科夫模型 作者:David S. Batista 选自:机器之心 本文首先简要介绍朴素贝叶斯,再将其扩展到隐马尔科夫模型.我们不仅会讨论隐马尔科夫模型的基本原理,同时还从朴素贝叶斯的角度讨论 ...

  6. 隐马尔科夫模型,第三种问题解法,维比特算法(biterbi) algorithm python代码

    上篇介绍了隐马尔科夫模型 本文给出关于问题3解决方法,并给出一个例子的python代码 回顾上文,问题3是什么, 下面给出,维比特算法(biterbi) algorithm 下面通过一个具体例子,来说 ...

  7. 隐马尔科夫模型——学习算法

    前言 隐马尔科夫模型有三个基本问题:概率计算问题,学习问题,预测问题.本博客介绍学习问题的监督学习算法和非监督学习算法(EM算法).阅读本文前请先学习基本概念. 什么是学习问题 学习问题是一直观测序列 ...

  8. python地图匹配_基于隐马尔科夫模型(HMM)的地图匹配(Map-Matching)算法

    1. 摘要 本篇博客简单介绍下用隐马尔科夫模型(Hidden Markov Model, HMM)来解决地图匹配(Map-Matching)问题.转载请注明网址. 2. Map-Matching(MM ...

  9. 隐马尔科夫模型(HMM)模型训练:Baum-Welch算法

    在上一篇博客中隐马尔科夫模型(HMM)原理详解,对隐马尔科夫模型的原理做了详细的介绍.今天,我们要对其中的模型训练算法Baum-Welch做一个实现,Baum-Welch算法可以在不知道状态序列的情况 ...

最新文章

  1. SSM项目整合Quartz
  2. 悟透LoadRunner - 什么是性能测试?
  3. centos 安装 py pyhs2
  4. 深入解读EOS源代码之——区块链内核
  5. 隐藏水滴屏的软件_突破屏下摄像头技术,vivo APEX 2020,开启全面屏手机黑科技!...
  6. RGB_D_开发征程(使用Kinect)
  7. 用python写九九乘法口诀表左上角_python打出九九乘法口诀表
  8. 再见!热血活力的深圳
  9. 在命令行到处MYSQL数据到EXCEL表
  10. java解析多层嵌套json字符串_Redis使用字符串和hash存储JSON,哪个更高效?
  11. c语言中的makefile编写步骤详解
  12. ppt流程图箭头分叉_箭头循环图ppt模板_PPT结构图制作中箭头跟着目标走的技巧_ppt箭头流程图模板_ppt箭头循环图...
  13. 透过数据看真相:手游市场趋势报告
  14. [年终总结]这就是2016的我
  15. 文本相似度计算——Simhash算法(python实现)
  16. Linux的介绍与应用
  17. 中兴通讯加入星策开源社区 携手推动企业智能化转型建设
  18. Running flutter pub get in flutter_app...卡死
  19. 你们要的华为hcia题库来了,华为数通,存储,云计算应有尽有快来点进来看看
  20. 一、新电脑入手的设置

热门文章

  1. PS网页设计小贴士——快速设计3D点阵字
  2. 2023云南大学考研择校
  3. echarts基本属性大全
  4. Bert的pooler_output是什么?
  5. DJ软件djay pro 2使用技巧
  6. EOS笔记2--同步主网与测试网
  7. 英雄联盟 python 刷等级_使用python3.7.2 实现大名鼎鼎的Elo Score等级分制度
  8. 威联通 ipv6设置
  9. Gitee任务和版本修改状态通过webhook推送给飞书和钉钉.同时@到指定的人
  10. EFK入门从头到尾一条龙服务