小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
一、任务分析和公式推导
想要词性标注的结果越好,即标注的结果概率最大,根据Noisy Channel Model可得:
其中为句子,
为句子中的单词的词性;
可视为Translate Model,
可视为Lauguage Model。
将表达式拆分:
根据马尔科夫假设,假设单词相互独立,当前单词只跟当前的词性相关:
为防止结果数值太小,结合对数函数严格递增的特性,对概率取对数得:
设:
设N为单词的数量,M为tag的数量,A表示在给定tag(词性)下,每个单词出现的概率,矩阵大小为M*N,
B表示tag之间的转换矩阵,矩阵大小为M*M,
Pi表示tag出现在句首的概率,矩阵大小为1*M。
二、使用Viterbi 算法(动态规划算法)求公式的最值
其中:dp[i,j]表示,将
赋标签
的情况下,从一开始到i的最好路径(即概率最大),将其转换为许多子问题,则:
三、代码
(一)数据
(二)构建词汇表和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])
复制代码