2022年 11月 9日

python的词性标注

词性标注

这里写目录标题

  • 词性标注
    • 词性标注的特殊问题
    • 词性标注的方法
    • 设计简单标注器
    • 常用标注器介绍
    • 词性标注器的应用
      • 词性分布
      • 基于词性标注 研究词的组合

词性标注:在给定的句子中判定每个词的语法范畴,确定词性并加以标注的过程。

难点:兼类词的消歧,未登录词标注

在某具体的语言环境中,一个词只能属于某一类词性。

词性标注的特殊问题

  1. 形态标准:不符合汉语划分;
  2. 意义标准:参考作用;
  3. 分布标准(功能标准);

词性标注的方法

  1. 基于规则的词性标注

  2. 基于机器学习的词性标注
    无监督学习——聚类方法
    半监督学习——自训练算法、多视角算法、直推式

  3. 基于规则与统计相结合的研究方法
    对句子的初始词性标注结果,首先规则消歧,再通过统计消歧,并对未登录词进行此行推测,最后进行人工校对,得到比较正确的标注结果。

  4. 基于感知机的标注方法
    输入:词的特征集
    输出:标注结果(词类)

马尔科夫链:将来的状态只与当前有关,短程依赖。
隐含马尔可夫链HMM
马尔科夫链:描述状态的转移,用转移概率描述;
一般随机过程:描述状态与观察序列间的关系,用观察值概率描述。

设计简单标注器

  1. 默认标注器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)) # 对标注器进行评估
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 正则表达式标注器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)) # 对标注器进行评估
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  1. 查询标注器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)) # 评估该标注器
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

随着词数增加,标注器性能显著增加,一般设置3000词左右较合适。这部分的高频词一般是话题无关的。

  1. 组合标注器
    理想的标注流程是:先使用查询标注器,若没查到,再使用默认标注器或者正则标注器。
# 之前的代码 略

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)) # 评估该标注器
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  1. 一元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)) # 评估
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    二元标注器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)) # 评估
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三元标注为Trigram n元标注为Ngram

    Bigram的问题数据稀疏:被标注的语料遇到新词,则无法正确标注。

  2. n元组合标注器
    Bigram在单独使用时标注比例很低。

常用标注器介绍

  1. 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')) # 字符串标注转换为元组形式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. thulac汉语词性标注工具
import thulac

thu = thulac.thulac()
# 结果:[['从', 'p'], ['繁体', 'n'], ['转换', 'v'], ['为', 'v'], ['简体', 'n'], ['。', 'w']]   
print(thu.cut("从繁体转换为简体。"))
  • 1
  • 2
  • 3
  • 4
  • 5
  1. jieba词性标注器
import jieba
from jieba import posseg

pos = list(jieba.posseg.cut())
  • 1
  • 2
  • 3
  • 4

词性标注器的应用

词性分布

在语料库中,查找最常见的词性。

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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

基于词性标注 研究词的组合

  1. 双词组合

查找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后的词的标注
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  1. 三词组合

找到三词组合,中间词是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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6