此部分基于词性标注的数学表示后,针对给定的语料,做一些viterbi算法的一些预处理。
给定的语料格式如下所示:
it/PRP
will/MD
introduce/VB
a/DT
new/JJ
incentive/NN
plan/NN
for/IN
advertisers/NNS
./.
其中每行是一个单词和其词性标注,用/分割,每个句子的结尾用./.作为结束标志。则基于上述说明,我们对训练语料进行预处理,代码如下所示:
# 词性与对应id的词典对应关系,比如tag2id={"NNP":0, "VBG":1, ..., } id2tag={0:"NNP", 1:"VBG", ..., }
tag2id, id2tag = {}, {}
# 词与对应id的词典对应关系
word2id, id2word = {}, {}
# 读取训练文件,做预处理
for line in open("traindata.txt"):
items = line.split("/")
word, tag = items[0], items[1].rstrip() # 提取每一行里面的单词和词性
if word not in word2id:
word2id[word] = len(word2id)
id2word[len(word2id)] = word
if tag not in tag2id:
tag2id[tag] = len(tag2id)
id2tag[len(id2tag)] = tag
M = len(word2id) # 词典的大小, num of words in dictionary
N = len(tag2id) # 词性的种类个数, num of tags in tag set
# print(tag2id)
# print(id2tag)
#
# print(M)
# print(N)
# 基于上述处理,构建pi、A、B
import numpy as np
pi = np.zeros(N) # pi标识每个词性出现在句子第一个位置的概率
A = np.zeros((N, M)) # A[i][j]给定tag i,出现单词j的概率
B = np.zeros((N, N)) # B[i][j]词性从状态i转移到j的概率
# 计算pi 、 A 、B
prev_tag = ""
for line in open("traindata.txt"):
items = line.split("/")
# 获取单词和词性对应的id
wordId, tagId = word2id[items[0]], tag2id[items[1].rstrip()]
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()
# normalize
pi = pi/sum(pi)
for i in range(N):
A[i] /= sum(A[i])
B[i] /= sum(B[i])
# print(pi)
# print(A)
# print(B)
打印pi结果如下所示:
[1.81324111e-01 0.00000000e+00 1.00049407e-02 3.33498024e-03
3.95256917e-03 3.68083004e-02 1.11660079e-01 3.66847826e-02
6.17588933e-04 3.81669960e-02 8.76976285e-03 5.18774704e-02
6.02766798e-02 2.47035573e-04 2.17267787e-01 0.00000000e+00
1.48221344e-03 6.05237154e-03 8.64624506e-04 2.47035573e-04
0.00000000e+00 4.73073123e-02 0.00000000e+00 7.16403162e-03
1.72924901e-03 2.09980237e-03 7.53458498e-02 6.36116601e-02
2.59387352e-03 1.85276680e-03 5.92885375e-03 1.97628458e-03
2.84090909e-03 0.00000000e+00 0.00000000e+00 2.71739130e-03
5.92885375e-03 5.92885375e-03 9.88142292e-04 3.70553360e-04
1.23517787e-04 0.00000000e+00 0.00000000e+00 1.85276680e-03
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00]
通过上述处理后,我们可以得到矩阵A、pi、B,及在上节中我们说明的值。其中A是词性为 \(t_i\)的词\(w_i\)的概率,\(\pi\)可以解释为开头的词性概率,B可解释为为词性\(t_{i-1}\)到词性\(t_i\)转移的概率。