词性标注
词性标注:在给定的句子中判定每个词的语法范畴,确定词性并加以标注的过程。
难点:兼类词的消歧,未登录词标注
在某具体的语言环境中,一个词只能属于某一类词性。
词性标注的特殊问题
- 形态标准:不符合汉语划分;
- 意义标准:参考作用;
- 分布标准(功能标准);
词性标注的方法
-
基于规则的词性标注
-
基于机器学习的词性标注
无监督学习——聚类方法
半监督学习——自训练算法、多视角算法、直推式 -
基于规则与统计相结合的研究方法
对句子的初始词性标注结果,首先规则消歧,再通过统计消歧,并对未登录词进行此行推测,最后进行人工校对,得到比较正确的标注结果。 -
基于感知机的标注方法
输入:词的特征集
输出:标注结果(词类)
马尔科夫链:将来的状态只与当前有关,短程依赖。
隐含马尔可夫链HMM
马尔科夫链:描述状态的转移,用转移概率描述;
一般随机过程:描述状态与观察序列间的关系,用观察值概率描述。
设计简单标注器
- 默认标注器nltk.DefaultTagger
只利用了词本身的统计信息。
nltk的评估依据是一个标准测试数据,由人手工标注。
import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist
tags = [tag for (word, tag) in brown.tagged_words(categories='news')]
word = FreqDist(tags).max()
# 结果:NN
print(word)
brown_sents = brown.sents(categories='news')
brown_tagged_sents = brown.tagged_sents(categories='news')
dt = nltk.DefaultTagger(word) # 以word作为标注器的输出,设计标注器
dt.tag(brown_sents[0]) # 对句子brown_sents[0]进行标注
# 结果:0.13089484257215028
print(dt.evaluate(brown_tagged_sents)) # 对标注器进行评估
- 正则表达式标注器nltk.RegexpTagger
利用词形知识初步提高性能。
定义正则模式:正则表达式之间有一定的次序,前者优先。
import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist
import re
patterns = [(r'.*ing$', 'VBG'), # gerunds 动名词
(r'.*ed$', 'VBD'), # simple past
(r'.*es$', 'VBZ'), # 3rd singular present
(r'.*ould$', 'MD'), # modals情态动词
(r'.*\'s$', 'NN$'), # possessive nouns名词所有格
(r'.*s$', 'NNS'), # plural nouns 复数名词
(r'^-?[0-9]+(.[0-9]+)?$', 'CD'), # cardinal numbers基数词
(r'.*', 'NN') # nouns (default)
]
brown_sents = brown.sents(categories='news')
brown_tagged_sents = brown.tagged_sents(categories='news')
rt = nltk.RegexpTagger(patterns) # 定义正则表达式标注器
rt.tag(brown_sents[0]) # 对句子brown_sents[0]进行标注
# 结果:0.20326391789486245
print(rt.evaluate(brown_tagged_sents)) # 对标注器进行评估
- 查询标注器nltk.UnigramTagger
利用词频知识进一步提高性能。
实现:对高频词进行专门标记,找出前N(如100)最高频词的最可能标注。
import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist
# 选择brown语料库中的词
fd = nltk.FreqDist(brown.words(categories='news'))
# 获得brown语料库中的词及其标注的分布
cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news')) # cfd是一个继承词典
# 结果:{'AT': 5558, 'AT-TL': 18, 'AT-HL': 4}
print(dict(cfd['the']))
# 单词词性AT出现了5888次,词性AT-TL出现了18次,AT-HL出现了4次
# 获取高频的N个词,并进行词的标注
N = 100
most_freq_words = [word for (word, num) in fd.most_common(N)]
likely_tags = dict((word, cfd[word].max()) for word in most_freq_words)
brown_sents = brown.sents(categories='news')
brown_tagged_sents = brown.tagged_sents(categories='news')
baseline_tagger = nltk.UnigramTagger(model=likely_tags) # 实现标注器
baseline_tagger.tag(brown_sents[0]) # 标注句子
# 结果:0.45578495136941344
print(baseline_tagger.evaluate(brown_tagged_sents)) # 评估该标注器
随着词数增加,标注器性能显著增加,一般设置3000词左右较合适。这部分的高频词一般是话题无关的。
- 组合标注器
理想的标注流程是:先使用查询标注器,若没查到,再使用默认标注器或者正则标注器。
# 之前的代码 略
btr = nltk.UnigramTagger(model=likely_tags, backoff=dt) # 查询标注器和默认标注器组合
btr.tag(brown_sents[0]) # 对句子brown_sents[0]进行标注
# 结果:0.5817769556656125
print(btr.evaluate(brown_tagged_sents)) # 评估该标注器
btr = nltk.UnigramTagger(model=likely_tags, backoff=rt) # 查询标注器和正则标注器组合
btr.tag(brown_sents[0]) # 对句子brown_sents[0]进行标注
# 结果:0.6498697217415518
print(btr.evaluate(brown_tagged_sents)) # 评估该标注器
-
一元Uni-gram 二元Bi-gram标注器
增加对上下文特性的考虑。在标注器的实现过程中,带标注的语料即是标注器的依据,根据每个词的标注频次,选择最高的作为其标注,这个过程称为“训练”。
一元标注器Unigram Tagging
siz = 100 train_sents = brown_tagged_sents[siz:] test_sents = brown_tagged_sents[:siz] ug = nltk.UnigramTagger(train_sents) # 训练 # 结果:[('the', 'AT'), ('man', 'NN'), ('is', 'BEZ')] print(list(ug.tag(['the', 'man', 'is']))) # 结果:0.8562610229276896 print(ug.evaluate(test_sents)) # 评估
二元标注器Bigram Tagging
bg = nltk.BigramTagger(train_sents) # 训练 # 结果:[('the', 'AT'), ('man', 'NN'), ('is', 'BEZ')] print(list(bg.tag(['the', 'man', 'is']))) # 结果:0.1318342151675485 print(bg.evaluate(test_sents)) # 评估
三元标注为Trigram n元标注为Ngram
Bigram的问题数据稀疏:被标注的语料遇到新词,则无法正确标注。
-
n元组合标注器
Bigram在单独使用时标注比例很低。
常用标注器介绍
- nltk的词性标注工具
word_lis = nltk.word_tokenize(str(text1)) # 词列表的构建
nltk.pos_tag(word_lis) # 词串标记工具
result = nltk.corpus.nps_chat.tagged_words()# 读取带标记的语料库nps_chat
# 结果:[('now', 'RB'), ('im', 'PRP'), ('left', 'VBD'), ...]
print(result)
# 结果:('fly', 'NN')
print(nltk.tag.str2tuple('fly/NN')) # 字符串标注转换为元组形式
- thulac汉语词性标注工具
import thulac
thu = thulac.thulac()
# 结果:[['从', 'p'], ['繁体', 'n'], ['转换', 'v'], ['为', 'v'], ['简体', 'n'], ['。', 'w']]
print(thu.cut("从繁体转换为简体。"))
- jieba词性标注器
import jieba
from jieba import posseg
pos = list(jieba.posseg.cut())
词性标注器的应用
词性分布
在语料库中,查找最常见的词性。
import nltk
from nltk.corpus import brown
brown_news_tagged = brown.tagged_words(categories='news')
tag_fd = nltk.FreqDist(tag for (word, tag) in brown_news_tagged)
# 结果:[('NN', 13162), ('IN', 10616), ('AT', 8893)]
print(tag_fd.most_common(3))
基于词性标注 研究词的组合
- 双词组合
查找often之后的词。
import nltk
from nltk.corpus import brown
text = brown.words(categories='news')
bitext = nltk.bigrams(text)
# 结果:['ambiguous', ',', 'hear', 'a', 'needs', 'that', 'in', 'enough', 'did', 'acceptable', 'mar', '.', 'obstructed', 'build']
ss = [word for word in bitext]
print([b for (a,b) in ss if a=='often']) # 得到全部紧邻在often后的词
bd = brown.tagged_words(categories='news')
bibd = nltk.bigrams(bd)
# 结果:['JJ', ',', 'VB', 'AT', 'VBZ', 'CS', 'IN', 'QLP', 'DOD', 'JJ', 'VB', '.', 'VBD', 'VB']
print([b[1] for (a,b) in bibd if a[0]=='often']) # 得到的是often后的词的标注
- 三词组合
找到三词组合,中间词是to,前后都是动词。
# 之前的代码 略
tribd = nltk.trigrams(bd)
lis = [(a[0],b[0],c[0]) for (a,b,c) in tribd if a[1].startswith('V') and c[1].startswith('V') and b[1]=='TO'] # 查找
# 结果:344
print(len(lis))