词性标注维特比算法实现
基于前几篇文章对维特比算法的说明,此文对维特比算法进行实现,并基于维特比算法实现给定语句的词性标注。关于\(pi,A,B\)的说明参考文章词性标注语料预处理实战,维特比相关算法说明参考词性标注维特比算法介绍
def log(v):
if v == 0:
return np.log(v+0.000001)
return np.log(v)
def vertibe(x, pi, A, B):
"""
:param x:输入的待预测词性的文本,例如 "I like NLP"
:param pi:初始的词性概率
:param A:给定词性,每个单词的概率
:param B:词性之间的状态转移概率
:return:
"""
# 处理输入的文本数,获取输入文本在上文处理的id号
x = [word2id[word] for word in x.split(" ")]
# 获取输入文本分词后的长度
T = len(x)
# dp[i][j] 标识第i个词的词性为第j个词性
dp = np.zeros((T, N))
ptr = np.array([[0 for x in range(N)] for y in range(T)])
# 计算第一个词在给定词性的概率
for j in range(N):
dp[0][j] = log(pi[j]) + log(A[j][x[0]])
for i in range(1, T): # 循环每一个单词
for j in range(N): # 每个词性
dp[i][j] = -99999999 # 设置一个很小的分值,作为后续计算每次的计算比较值
for k in range(N): # 循环每个词性,计算从上一个词性到当前词性的值
score = dp[i-1][k] + log(B[k][j]) + log(A[j][x[i]])
if score > dp[i][j]:
dp[i][j] = score
ptr[i][j] = k # 记录得分最高的值是从上一层的那个节点过来的
# 把最好的词性标注序列打印出来
best_seq = [0]*T
# step 1 找出对应于最后一个词的词性
best_seq[T-1] = np.argmax(dp[T-1])
# step 2 通过循环,从后到前依次求出每个单词的词性
for i in range(T-2, -1, -1):
best_seq[i] = ptr[i+1][best_seq[i+1]]
# 打印预测的词性序列
for i in range(len(best_seq)):
print(id2tag[best_seq[i]])
x = "Newsweek , trying to keep pace with rival Time magazine , announced new advertising rates for 1990"
vertibe(x, pi, A, B)
运行结果如下
NNP
,
VBG
TO
VB
NN
IN
JJ
NN
NN
,
VBD
JJ
NN
NNS
IN
CD
该测试语料是从训练语料中提取的,我们看下训练语料的标注,如下所示
Newsweek/NNP
,/,
trying/VBG
to/TO
keep/VB
pace/NN
with/IN
rival/JJ
Time/NNP
magazine/NN
,/,
announced/VBD
new/JJ
advertising/NN
rates/NNS
for/IN
1990/CD
前面是词,后面是该词的词性,从对比看,词性标注的预测结果相对准确。
备注:此章节实现参考了贪心学院的相关视频课程和代码,在此标注。