赞
踩
上一次实验我们介绍了隐马尔可夫模型的基本原理,以及根据具体案例来分析其应用,详细介绍了隐马尔科夫模型所包含的三个重要概率分布矩阵,初始化概率矩阵,状态转移概率矩阵,发射概率矩阵。以及其如何计算的方法。我们在上次实验的代码里,将训练好的三个矩阵用python的pumkle的模块进行了存储,这次实验我们着重介绍,隐马尔可夫模型在分词中的应用。
内容:已知语料库中有且仅有如下3个句子:
商品 和 服务
商品 和服 物美价廉
服务 和 货币
应用隐马尔可夫模型和维特比算法给出‘商品和货币’这句话的分词结果。
我们在此处应用在上次博客中提到的方法,根据输入隐马尔科夫模型的分好词的句子。
首先我们运行上次博客介绍的代码。记得要在该代码同目录下,新建文件夹,重命名为mat_pickle,分别输入“商品 和 服务”,“商品 和服 物美价廉”,“服务 和 货币”。
该代码主要思路如下:
然后读者可复制以下的代码,然后运行该代码,该代码可以自动读取上个代码保留的文件,然后读取存储的模型,进而对新的句子进行分词。
该代码思路如下:
维特比算法是一种采用了动态规划的算法,他在隐马尔可夫模型中的应用十分广泛,它的大致思想就是对每一个状态记录当前状态和之后状态的所有情况,选取最优解。它是一种对于枚举方法的改进(即计算出所有情况,然后选取最优解),在问题规模很大时维特比算法相比于暴力枚举将展现其强大的优势。
代码的维特比算法借鉴了该代码,原文链接:https://blog.csdn.net/youfefi/article/details/74276546
import numpy as np import pickle def solve_tag(answer,sentence): result = [] hidden_state = ["B", "M", "E", "S"] for i in range(len(answer)): if(hidden_state[int(answer[i])]=='E' or hidden_state[int(answer[i])]=='S'): result.append(sentence[i]) result.append(" ") else: result.append(sentence[i]) return result def compute(obs, states, start_p, trans_p, emit_p): # max_p(3*2)每一列存储第一列不同隐状态的最大概率 max_p = np.zeros((len(obs), len(states))) #print("max_p",max_p) # path(2*3)每一行存储上max_p对应列的路径 path = np.zeros((len(states), len(obs))) #print("path",path) # 初始化 for i in range(len(states)): max_p[0][i] = start_p[i] * emit_p[i][obs[0]] path[i][0] = i #print("max_p", max_p) #print("path", path) for t in range(1, len(obs)): newpath = np.zeros((len(states), len(obs))) for y in range(len(states)): prob = -1 for y0 in range(len(states)): nprob = max_p[t-1][y0] * trans_p[y0][y] * emit_p[y][obs[t]] if nprob > prob: prob = nprob state = y0 # 记录路径 max_p[t][y] = prob for m in range(t): newpath[y][m] = path[state][m] newpath[y][t] = y path = newpath #print("path",path) max_prob = -1 path_state = 0 # 返回最大概率的路径 for y in range(len(states)): if max_p[len(obs)-1][y] > max_prob: max_prob = max_p[len(obs)-1][y] path_state = y #print("path_state",path_state) return path[path_state] if __name__ == "__main__": BMES = [] #emit_mat = pd.DataFrame(index=['B','M','E','S']) #new_sentence = input("请输入你要分词的句子:") #new_sentence = "商品和货币" print("正在读取本地模型矩阵...") with open(r'mat_pickle/init_mat.pkl', "rb") as f0: init_mat = np.array(list(pickle.load(f0).values())) with open(r'mat_pickle/trans_mat.pkl', "rb") as f1: init_trans_mat = np.array(list(pickle.load(f1).values())) with open(r'mat_pickle/emit_mat.pkl', "rb") as f2: init_emit_mat = pickle.load(f2) catalog = list(init_emit_mat) trans_mat = [] emit_mat = [] hidden_state = ["B", "M", "E", "S"] for item in init_trans_mat: trans_mat.append(np.array(list(item.values()))) for i in hidden_state: emit_mat.append(np.array(list(init_emit_mat.loc[i]))) emit_mat = np.array(emit_mat).reshape(4,-1) #print(init_mat) #print(trans_mat) #print(emit_mat) print("读取模型矩阵成功!") print("目前模型的汉字库",catalog) while(1): new_sentence = input("请输入你要分词的句子(如:商品和货币)输入0结束分词功能:") if (new_sentence == '0'): print("输入结束!") break state_s = [0,1,2,3] original = [catalog.index(i) for i in new_sentence] #print(original) #print(hidden_state) result = compute(original, state_s, init_mat, trans_mat, emit_mat) #print(result) answer = solve_tag(result,new_sentence) #print(answer) print("分词的结果为:") for item in answer: print(item,end='') print("\n")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。