2020/11/18 python实现词性标注(含词库文件)


问题描述

给定词库traindata.txt(提取码为r9px),预测字符串x = 'The ad is increasing .'的词性。

问题分析

根据博客https://www.cnblogs.com/pinking/p/8531405.html的内容可知,这是一个典型的hmm预测问题。因此我们需要先基于词库,计算出hmm模型的三个参数(A, B, π),然后使用viterbi算法进行词性预测。

求解步骤

1.读取词库traindata.txt,统计出四个字典:tag2id,id2tag,word2id,id2word

代码如下:

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

得到的四个字典的形式如下图所示:
在这里插入图片描述

2.计算hmm模型的三个参数(A, B, π)

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])

3. viterbi算法预测句中词的词性

3.1 分析

viterbi算法是一种动态规划的算法,其核心思想是:先求出起始位置到下一状态的最优路径,然后基于这个最优路径的值,继续求起始位置到下下一状态的最优路径,依此类推。当然每个最优化问题中“优”的评判标准不同。在词性标注问题中,其评判条件如下图箭头位置所示:
在这里插入图片描述
(图片引用于早期保存的某博客的学习笔记,链接忘记存了)
从上图可以看到,为了简化运算、并且放大概率值,公式对矩阵增加了log运算,这也是编码中需要注意的点。

3.2 代码示例

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))

运行结果如下:
在这里插入图片描述

4 推荐文章

[1] viterbi算法词性标注
[2] 维特比算法实现词性标注
[3] 课程讲解

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值