本文所用训练集:
链接:https://pan.baidu.com/s/1fK--_PrEhckKUSrajHGkEw
提取码:aehg
“词性标注”的国内外研究现状:
一、维特比算法是什么
二、训练集介绍
三、使用维特比算法进行词性标注(代码)
总结
自从上世纪60年代 Brown语料库建立以来,计算机自动词性标注技术发展迅速,截至目前国内外出现了众多的计算机自动词性标注技术,根据这些技术所依赖的理论和方法,可以将词性标注方法分为以下几类:
1. 基于规则的词性标注方法
基于规则的方法主要依靠人工制定的排歧规则数据库,这些规则说明了消除歧义的条件。如果在词性标注时遇到歧义词,就依次对排歧规则库中包含的语义规则进行对歧义词含义进行匹配,如果能够成功匹配且没有与任何语义规则相悖,则说明完成排歧,否则说明排歧工作失败。
2. 基于统计的词性标注方法
使用统计方法进行词性标注例需要一个事先标注好的语料库作为训练语料库,并根据单词所处的上下文信息,计算某一给定单词具有某词性的概率。例如,隐马尔可夫模型。
3. 基于规则与统计结合的综合算法
基于规则和统计相结合的词性标注方法融合了规则和统计两种词性标注方法。与基于规则的标注算法相似,算法要根据规则来决定一个有歧义的单词应该具有什么样的标记;与随机标注算法相似,算法中的规则可以由前面已经标注好的训练语料库自动地推理出来。从而能够利用两者优势,对现有的语言规则加以利用,还能结合统计方法在获取语言知识较为客观和覆盖率高的优势。
4. 基于转换的错误驱动学习方法
由于人工获取语言规则具有很大的困难,所以1995年Eric Brill提出了一种基于转换的错误驱动方法来代替人工制定语言规则,使得系统能够从训练语料中自动获取转换规则。这样获取的规则具有更高的准确性和适用性,该方法从大规模词性标注语料库中通过模版采用错误驱动的方式学习到大规模的规则,最后使用这些规则对文本进行词性标注。该方法解决了各规则之间的冲突问题,节省了人工制定规则所需的人力物力。
因为词性细分为几十种,而每个词汇都需要进行标注,传统的遍历法实在是太低效了,我们要想实现一个句子的最优词性标注(即概率值最大的词性搭配),就可以借助维特比算法更高效地解决。维特比算法的目的就是以较少的资源消耗,寻找到最优路径。
具体算法原理有一点点复杂,在这里给大家两个链接,方便各位学习:
通俗讲解维特比算法:https://zhuanlan.zhihu.com/p/28274845
如何通俗地讲解 viterbi 算法:https://www.zhihu.com/question/20136144
本次处理中用到了词性标注训练集word-cixing.txt,其中包含很多已经标注好的词汇。
链接:https://pan.baidu.com/s/1fK--_PrEhckKUSrajHGkEw
提取码:aehg
训练集预览:
其中 ‘ / ’ 左侧为词汇,右侧为词性。
导入训练集,形成词典和词性合集,并规定模型参数的计算方法:
其中模型有三个参数pi、A、B,自定义的log方法是防止矩阵中出现0,使得不能进行log运算。
import numpy as np
tag_id, id_tag = {}, {}
word_id, id_word = {}, {}
for line in open('word-cixing.txt'):
items = line.split('/')
word, tag = items[0], items[1].rstrip() #抽取每一行的词汇及词性
if word not in word_id:
word_id[word] = len(word_id)
id_word[len(id_word)] = word
if tag not in tag_id:
tag_id[tag] = len(tag_id)
id_tag[len(id_tag)] = tag
M = len(word_id) #词典的大小
N = len(tag_id) #词性的种类数
pi = np.zeros(N)
A = np.zeros((N, M))
B = np.zeros((N, N))
pre_tag = ""
for line in open('word-cixing.txt'):
items = line.split('/')
wordId, tagId = word_id[items[0]], tag_id[items[1].rstrip()]
if pre_tag == '':
pi[tagId] += 1
A[tagId][wordId] += 1
else:
A[tagId][wordId] += 1
B[tag_id[pre_tag]][tagId] += 1
if items[0] == '.':
pre_tag = ''
else:
pre_tag = items[1].rstrip()
pi = pi/sum(pi)
for i in range(N):
A[i] /= sum(A[i])
B[i] /= sum(B[i])
def log(v):
if v == 0:
return np.log(0.00001)
else:
return np.log(v)
定义维特比算法:
def viterbi(x, pi, A, B):
x = [word_id[word] for word in x.split(' ')]
T = len(x)
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] = -999
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
best_seq[T-1] = np.argmax(dp[T-1])
for i in range(T-2,-1,-1):
best_seq[i] = ptr[i+1][best_seq[i+1]]
result = [id_tag[best_seq[i]] for i in range(len(best_seq))]
return result
输入自定义文本,进行词性标注:
x = 'The best feeling in the world is when you know your heart is smiling and never put off what you can do today until tomorrow'
result = viterbi(x, pi, A, B)
print("句子:")
print(x)
x=x.split()
result_data = dict(zip(x, result))
print("词性:")
print(result)
print('\n')
print("句中单词的词性标注:")
print(result_data)
词性标注结果:
代码是借鉴网络上大佬们的,我把这个方法实践了一下,把数据集和代码分享给各位。