词性标注维特比算法实现

基于前几篇文章对维特比算法的说明,此文对维特比算法进行实现,并基于维特比算法实现给定语句的词性标注。关于\(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

前面是词,后面是该词的词性,从对比看,词性标注的预测结果相对准确。

备注:此章节实现参考了贪心学院的相关视频课程和代码,在此标注。

posted @ 2020-07-22 21:53  yhzhou  阅读(260)  评论(0编辑  收藏  举报