拼音输入法的简单实现可以归结为使用维特比算法求解汉字隐马尔可夫模型的问题:将用户输入的拼音转换为字层,使用维特比算法求解得到概率最大的一个“字链”,这个“字链”便是拼音输入法输出的文字。主要的几个步骤包括:
1、语料数据的预处理:把语料内容从文件列表中抽取出来,分句,去掉非中文字符。
2、在所有语料中,计算每个汉字的出现频次。
3、在所有语料中,计算当前汉字与其前面的汉字共同出现的频数,并计算其频率。
4、建立输入拼音与汉字的匹配关系,构造输入拼音对应汉字的隐马尔科夫模型。
5、使用维特比算法求解,得到概率最大的一个“字链”,取这个“字链”为输出的句子。
6、测试准确率。
1 代码构造
根据需求和实现步骤,写3个python程序。
第一个根据输入的语料库,计算汉字出现的频次、汉字与前一个汉字共同出现的频次和语料库的总字数。
第二个,首先根据“拼音汉字表”构造拼音与汉字的对应关系,将用户输入的拼音通过这个对应关系形成一个隐马尔科夫模型。根据第一个程序得出的结果,使用维特比算法,计算得到概率最大的“字链”,将这个“字链”输出为句子。
第三个,使用测试数据集,测试输入法的准确率和整句准确率。
代码结构如下。
2 实现过程
2.1 数据预处理
模型使用2016年2月、4-11月共9个月的新浪新闻语料数据进行模型训练。在训练之前,使用re.split()对语料中每一条新闻进行分句,分句依据为特定的标点符号,作为分句的标点为:(1)中文标点“:”、“。”、“……”、“,”、“?”、“、”(2)英文标点:“:”、“,”“!”、“?”。
由于只考虑6763个一二级汉字,为提高模型的可靠性,在分句时,如果这句话出现基本汉字之外的汉字,则不将这句话纳入模型训练。另外,使用“零一二三四五六七八九”代替阿拉伯数字“123456789”。同时,在每一句话中去掉所有非中文字符。对每一个数据集的每一条新闻都做同样的分句和数据处理,得到训练句子集。
2.2 生成汉字频数矩阵
对于已经得到的句子集合,以一二级汉字为统计对象,统计每个汉字的频数、每个汉字出现在句首的频数、当前汉字与前一汉字共同出现的频数、所有汉字的累计出现频数,分别定义hz_array、head_array、hz_matrix和totalNum 4个变量来存储这些数据。hz_array、head_array是数组形式,hz_matrix是矩阵形式。
2.3 生成汉字的隐马尔科夫模型
根据拼音汉字表,生成拼音与汉字对应关系的字典,并将输入的每一个拼音转化为对应的所有汉字。假设在一个句子中,每一个汉字的出现仅与前一个汉字有关,以每一个拼音所对应的汉字作为字链中的一层,生成汉字的隐马尔科夫模型。句首汉字的出现概率与其自身出现的概率与出现在句首的概率有关,用λ1来调节。同时,在计算概率时,将相应汉字的频次从各频次矩阵中提取出来,计算各个汉字出现的频率。由于总的汉字数超过4亿,在这里将上述两个概率以频率近似以频率代替。
在完成计算后,得到汉字的隐马尔科夫模型λ=(A,B,π),其中,状态转移矩阵A为当前汉字与前一汉字共同出现的概率矩阵,观测矩阵B为当前汉字出现的概率。初始矩阵π为句首汉字概率矩阵。其计算公式如下:
汉字的隐马尔科夫链如下图。
2.4 构建维特比函数
在拼音输入时,使用.lower()函数将输入的拼音转化为小写。
(1)对第一个节点,有:
若只有一个拼音输入,取δ1(i)最大的节点,即:
当输入两个以上的汉字时,先考虑句首汉字的概率,在完成过程(1)的基础上,完成如下过程。
(2)从第2个节点开始,有:
(3)终止,得到:
(4)通过iT*,对t=T-1, T-2,...,1进行最优路径回溯:
通过以上过程,得到字链的最佳路径I*=(i1*,i2*,...iT*),由I*查找对应的汉字,即可以组成输出的句子。
在写代码时,和
放在同一个矩阵p中。
2.5 构造测试函数
使用Levenshtein.hamming()计算实际汉字和拼音输入法输出汉字之间对应位置上不同字符的个数,用该段汉字总数减去不相符汉字的总数,得到该段汉字字符相同的汉字数。对每段汉字进行上述操作,加总除以总字数,得到准确率。
整句准确率以完全相同的句子数量除以句子总数得到。
3 实现效果
在实现上,构建了test_input()和test_accuracy()两个函数。test_input()实现在命令行中输入拼音,输出汉字的效果。
test_accuracy()用作准确率测试。使用拼音数据input_domo1.txt进行测试,取λ1=0.8,准确率为78.1%,整句准确率为25.6%。
使用新浪新闻的拼音数据input_domo2.txt测试,取λ1=0.5,拼音输入法准确率达到86.4%,整句准确率达到47.4%。
4 效果好的和效果差的,对比分析
在未分句时,使用整段新闻去掉标点和生僻字后得到的输出汉字,输入拼音“wo ai ni”会出现“我哎你”的情况。
分析发现,出现在一句话的句末的频次较高的字与出现在句前频次较高的字会有较高的概率共同出现在一起。所以,最终在计算各汉字频次时,使用分句的形式进行。为提高准确率,把阿拉伯数字转化为汉字数字,当句子中出现不在一二级汉字表中的汉字时,不将这句话纳入计算中。虽然计算时间基本不变,但是计算准确率得到提高。
同样,由于训练语料库的特点,与训练语料库同一来源新浪新闻测试集的准确率显著高于其他随机输入的拼音测试集。对于新闻中出现的热词准确率很高。
5 对照参数选择,性能分析
更改值,使用拼音数据input_domo1.txt进行测试,发现准确率变化幅度不大(如下图),但是取λ1=0.8时,准确率能够达到一个极大值。
6 总结收获
这是我人工智能课的第一次大作业,花了很多时间,也学到了不少东西。我这门课三次作业成绩也都还不错,发上来一是为了记录在公众号上,充实一下公众号的内容,提高一下公众号水平,二是也是提高我自己的自信:文科生也能学好数学,写好代码……
实践是最好的老师。通过本次学习,提高了对马尔科夫过程、隐马尔科夫模型、维特比算法的理解,对python的编程也更为熟练。
同时,由于数据量较大,写循环函数时代码极容易出错,应该在完成一段代码后立即测试。在调试代码的过程中,曾出现过汉字与前一个汉字共同出现次数大于单个汉字出现次数的情况,原因在于在计算频次时有一个变量出现错误。另外,在维特比算法的计算过程中,出现的index较多,容易弄乱,在循环计算中对应关系也应该小心,否则极易出现错误。付出极高的时间成本。
另外,对于变量的命名最好规范,做好规划,否则变量太多后容易出错。
8 改进方案
备选汉字可以不局限于一二级汉字表,使用包含20902个汉字的基本汉字表,可以提高输入法的适用性。另外,语料库可以不局限于新闻语料,类型更为多样的语料库可以提高输出句子的准确率和整句正确率。基于字的二元模型可以换成三元甚至更多,也能够进一步提高句子的准确率和整句正确率。