赞
踩
给定词库traindata.txt(提取码为r9px),预测字符串x = 'The ad is increasing .'的词性。
根据博客https://www.cnblogs.com/pinking/p/8531405.html的内容可知,这是一个典型的hmm预测问题。因此我们需要先基于词库,计算出hmm模型的三个参数(A, B, π),然后使用viterbi算法进行词性预测。
代码如下:
import numpy as np
tag2id,id2tag={},{}
word2id,id2word={},{}
with open('traindata.txt','r') as f:
for line in f.readlines():
items=line.split('/')
word,tag=items[0],items[1].rstrip()
if word not in word2id.keys():
word2id[word]=len(word2id)
id2word[len(id2word)]=word
if tag not in tag2id.keys():
tag2id[tag]=len(tag2id)
id2tag[len(id2tag)]=tag
得到的四个字典的形式如下图所示:
word_number=len(word2id) tag_number=len(tag2id) A = np.zeros((tag_number, word_number)) #发射矩阵 B=np.zeros((tag_number,tag_number))#状态转移矩阵 L=np.zeros(tag_number) #初始状态矩阵 pre_tag='' with open('traindata.txt','r') as f: for line in f.readlines(): items=line.split('/') wordId,tagId=word2id[items[0]],tag2id[items[1].rstrip()] if pre_tag=='': #表示是在句首位置,此时统计发射矩阵和初始状态矩阵 L[tagId]+=1 A[tagId][wordId]+=1 else: #表示在句中位置,此时统计发射矩阵和状态转移矩阵 A[tagId][wordId] += 1 B[tag2id[pre_tag]][tagId]+=1 if items[0]=='.': #说明这个句子结束,到了下一个句子 pre_tag='' else: pre_tag=items[1].rstrip() #将矩阵中的值转换成概率 L/=sum(L) for i in range(tag_number): A[i] /=sum(A[i]) B[i] /=sum(B[i])
viterbi算法是一种动态规划的算法,其核心思想是:先求出起始位置到下一状态的最优路径,然后基于这个最优路径的值,继续求起始位置到下下一状态的最优路径,依此类推。当然每个最优化问题中“优”的评判标准不同。在词性标注问题中,其评判条件如下图箭头位置所示:
(图片引用于早期保存的某博客的学习笔记,链接忘记存了)
从上图可以看到,为了简化运算、并且放大概率值,公式对矩阵增加了log运算,这也是编码中需要注意的点。
def log(v): if v==0: #为了避免np.log函数报错 return np.log(0.00001) else: return np.log(v) def viterbi(x,L,A,B): seq2id=[word2id[i] for i in x.split()] lay_number=len(seq2id) P=np.zeros((lay_number,tag_number)) D=np.zeros((lay_number,tag_number)) for i in range(tag_number): P[0][i]=log(L[i])+log(A[i][seq2id[0]]) D[0][i]=-1 for layer in range(1,lay_number,1): for i in range(tag_number): #当前节点 probilities = [] for j in range(tag_number):#前一个节点 probilities.append(P[layer-1][j]+log(B[j][i])+log(A[i][seq2id[layer]])) P[layer][i] = np.max(probilities) D[layer][i] = np.argmax(probilities) best_seq=[0]*lay_number best_seq[lay_number-1]=np.argmax(P[lay_number-1]) #反推出最优路径 for layer in range(lay_number-2,-1,-1): best_seq[layer]=int(D[layer+1][int(best_seq[layer+1])]) #求出最终的词性标注结果 best_seq=[id2tag[best_seq[i]] for i in range(len(best_seq))] return best_seq
测试:
if __name__ == '__main__':
x = 'The ad is increasing .'
print("标注结果为:",viterbi(x,L,A,B))
运行结果如下:
[1] viterbi算法词性标注
[2] 维特比算法实现词性标注
[3] 课程讲解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。