NLP实战-词性标注-维特比算法

1,441 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

一、任务分析和公式推导

想要词性标注的结果越好,即标注的结果概率最大,根据Noisy Channel Model可得:

image.png

其中为句子,为句子中的单词的词性;可视为Translate Model, 可视为Lauguage Model。

将表达式拆分:

image.png

根据马尔科夫假设,假设单词相互独立,当前单词只跟当前的词性相关:

image.png

为防止结果数值太小,结合对数函数严格递增的特性,对概率取对数得:

image.png

设:

image.png

设N为单词的数量,M为tag的数量,A表示在给定tag(词性)下,每个单词出现的概率,矩阵大小为M*N,

image.png

B表示tag之间的转换矩阵,矩阵大小为M*M,

image.png Pi表示tag出现在句首的概率,矩阵大小为1*M。

image.png

二、使用Viterbi 算法(动态规划算法)求公式的最值

image.png 其中:dp[i,j]表示,将赋标签的情况下,从一开始到i的最好路径(即概率最大),将其转换为许多子问题,则:

image.png

三、代码

(一)数据

image.png

(二)构建词汇表和tag表

# 构建词汇表和tag表 
# maps tag to id . tag2id:{"VB":0,"NNP":1...},id2tag:{0:"VB",1:"NNP"} tag2id ,id2tag = {},{} # maps word to id 
word2id ,id2word = {},{} 
for line in open("./data/08/traindata.txt"): i
    tems = line.split("/") 
    # 获取每一行的单词和词性,rstrip():删除末尾指定字符,默认为空格 
    word,tag = items[0],
    items[1].rstrip() 
    if word not in word2id: 
        word2id[word]=len(word2id) 
        id2word[len(id2word)] = word 
    if tag not in tag2id: tag2id[tag] = len(tag2id) 
        id2tag[len(id2tag)] = tag

(三)计算模型参数

#计算模型的参数:A,B,Pi矩阵
N = len(word2id) # N: 词典的大小、# of words in dictionary M = len(tag2id) # M: 词性的种类个数 # of tags in tag set
# A[i][j]: 给定tag i, 出现单词j的概率。 N: # of tags M: # of words in dictionary 
A = np.zeros(M,N)
# B[i][j]: 之前的状态是i, 之后转换成转态j的概率 N: # of tags 
B = np.zeros(M,M) 
# 每个词性出现在句子中第一个位置的概率, N: # of tags pi[i]: tag i出现在句子中第一个位置的概率 
Pi = np.zeros(M)
prev_tag = ""
for line in open("./data/08/traindata.txt"): 
items = line.split('/') 
wordId,tagId = word2id[items[0]],tag2id[items[1]] 
if prev_tag == "":#表示是句子开头 
    Pi[tagId] += 1 
    A[tagId][wordId] += 1 
else: 
    A[tagId][wordId] += 1 
    B[tag2id[prev_tag]][tagId] += 1 
if items[0] == ".": 
    prev_tag = ""
else: 
    prev_tag = items[1].rstrip()
# 标准化
Pi = Pi/sum(Pi) 
for i in range(M): 
    A[i] /= sum(A[i]) 
    B[i] /= sum(B[i])

(四)动态规划

平滑操作

image.png

viterbi算法

image.png

image.png

(五)测试

image.png