前言

5 分类和标注词汇

NLP基本技术

  • 序列标注
  • N-gram模型
  • 回退和评估

将词汇按他们的词性(parts-of-speech,POS)分类并标注,

此过程叫做词性标注(parts-of-speech tagging,POS tagging)

词性 也称 词类、词汇范畴

重点

  1. 利用标记
  2. 自动标注文本

5.1 使用词性标注器

词性标注器(parts-of-speech tagger,POS tagger) 处理一个次序列,为每个词附加一个词性标记,也可以对未知词的认知过程建模

1
2
3
4
5
6
7
8
9
import nltk

text = nltk.word_tokenize("And now for something completely different")
pos_tagger_result = nltk.pos_tag(text)
print(pos_tagger_result)
"""
[('And', 'CC'), ('now', 'RB'), ('for', 'IN'),
('something', 'NN'), ('completely', 'RB'), ('different', 'JJ')]
"""
1
2
3
4
# 查看标记的文档
nltk.help.upenn_tagset('RB')
nltk.help.upenn_tagset('NN.*')
# nltk.[name].readme() # the name is corpus name
1
2
3
4
5
# 同形同音异义词
text = nltk.word_tokenize("They refuse to permit us to obtain the refuse permit")
pos_tagger_result = nltk.pos_tag(text)
print(pos_tagger_result)
# refUSE->VBP REFuse->NN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
text = nltk.Text(word.lower() for word in nltk.corpus.brown.words())
text.similar('woman') # 名词
text.similar('bought') # 动词
text.similar('over') # 介词
text.similar('the') # 限定词
# 该方法为词 w 找出所有上下文 w1ww2,再找出所有想同上下文中的词 w',即w1w'w2
"""
man time day year car moment world house family child country boy state job place way war girl work word

made said done put had seen found given left heard was been brought set got that took in told felt

in on to of and for with from at by that into as up out down through is all about

a his this their its her an that our any all one these my in your no some other and
"""

5.2 标注语料库

表示已经标注的标识符

NLTK约定:已标注的标识符使用 (标识符,标记) 表示

1
2
3
# 已标注标志符的标准字符串创建一个特殊元组
tagged_token = nltk.tag.str2tuple('fly/NN')
print(tagged_token)

需要对句子进行标注,然后使用str2tuple

读取已标注的语料库

NLTK中包括若干已标注了词性的语料库(词性标记使用大写)

只要语料库包含已标注的文本,NLTK的语料库接口都有一个 tagged_words()方法

1
2
print(nltk.corpus.nps_chat.tagged_words())
# [('now', 'RB'), ('im', 'PRP'), ('left', 'VBD'), ...]

NLTK使用内置影射到简化的标记集

1
2
3
4
5
6
7
8
9
10
print(nltk.corpus.brown.tagged_words())
print(nltk.corpus.brown.tagged_words(tagset='universal'))
print(nltk.corpus.treebank.tagged_words())
print(nltk.corpus.treebank.tagged_words(tagset='universal'))
"""
[('The', 'AT'), ('Fulton', 'NP-TL'), ...]
[('The', 'DET'), ('Fulton', 'NOUN'), ...]
[('Pierre', 'NNP'), ('Vinken', 'NNP'), (',', ','), ...]
[('Pierre', 'NOUN'), ('Vinken', 'NOUN'), (',', '.'), ...]
"""

使用标记集的帮助函数和readme()方法中的文档也可以查看 #xxliu

其他几种语言的已标注语料库

1
2
3
4
5
6
7
8
9
10
11
12
print(nltk.corpus.sinica_treebank.tagged_words())  # 中文
print(nltk.corpus.indian.tagged_words()) # 印地语
print(nltk.corpus.mac_morpho.tagged_words()) # 葡萄牙语
print(nltk.corpus.conll2002.tagged_words()) #
print(nltk.corpus.cess_cat.tagged_words()) #
"""
[('一', 'Neu'), ('友情', 'Nad'), ('嘉珍', 'Nba'), ...]
[('মহিষের', 'NN'), ('সন্তান', 'NN'), (':', 'SYM'), ...]
[('Jersei', 'N'), ('atinge', 'V'), ('média', 'N'), ...]
[('Sao', 'NC'), ('Paulo', 'VMI'), ('(', 'Fpa'), ...]
[('El', 'da0ms0'), ('Tribunal_Suprem', 'np0000o'), ...]
"""

正确设置环境,有对应编辑器和字体,则能够已可读方式显示

否则以十六进制显示

将已标注的词划分成句子

tagged_sents()

简化的词性标记集

表5-1 简化的标记集 P(200)

1
2
# 图形化 POS 一致性工具
nltk.app.concordance() # 寻找任一词和 POS 标记的组合

名词,动词,形容词和副词

名词一般指人、地点、事情和概念。
可能出现在限定词和形容词之后,可以使动词的主语或宾语

  • 表 5-2 名词的句法模式 P(201)
  • 表 5-3 动词的句法模式 P(202)

词性标注中 VBD(过去式) VBN(过去分词)

除此之外还有几个封闭的词类,如介词、冠词(也称限定词,a,an,the)、情态动词(should,may)、人称代词(she,they)
每个词典和语法对这些词的分类都不同

未简化的标记

找出最频繁的名词标记的程序

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
27
28
def findtags(tag_prefix, tagged_text):
cfd = nltk.ConditionalFreqDist(
(_tag, word) for (word, _tag) in tagged_text if _tag.startswith(tag_prefix)
)
# keys() 不让切片,转成list
return dict((_tag, list(cfd[_tag].keys())[:5]) for _tag in cfd.conditions())


tagdict = findtags('NN', nltk.corpus.brown.tagged_words(categories='news'))
for tag in sorted(tagdict):
print(tag, tagdict[tag])
"""
NN ['investigation', 'primary', 'election', 'evidence', 'place']
NN$ ["ordinary's", "court's", "mayor's", "wife's", "governor's"]
NN$-HL ["Golf's", "Navy's"]
NN$-TL ["Department's", "Commissioner's", "President's", "Party's", "Mayor's"]
NN-HL ['Merger', 'jail', 'Construction', 'fund', 'sp.']
NN-NC ['ova', 'eva', 'aya']
NN-TL ['County', 'Jury', 'City', 'Committee', 'Court']
NN-TL-HL ['Mayor', 'Commissioner', 'City', 'Oak', 'Grove']
NNS ['irregularities', 'presentments', 'thanks', 'reports', 'voters']
NNS$ ["taxpayers'", "children's", "members'", "women's", "years'"]
NNS$-HL ["Dealers'", "Idols'"]
NNS$-TL ["States'", "Women's", "Princes'", "Bombers'", "Falcons'"]
NNS-HL ['Wards', 'deputies', 'bonds', 'aspects', 'Decisions']
NNS-TL ['Police', 'Roads', 'Legislatures', 'Bankers', 'Reps.']
NNS-TL-HL ['Nations']
"""

探索已标注的数据库(略)

5.3 使用 Python 字典影射词及其属性

索引链表 VS 字典(略)

表 5-4 语言学对象从键到值的影射 P(208)

Python 字典(略)

定义字典(略)

  • pos = {'colorless':'ADJ','ideas':'N'}
  • pos = dict(colorless='ADJ',ideas='N')

    默认字典(略)

    nltk的默认字典必须提供一个参数
  • 提供类型(int,float,str,list,dict,tuple)

    1
    2
    3
    4
    freq = nltk.defaultdict(int)
    freq['ideas'] # 0
    pos = nltk.defaultdict(list)
    pos['ideas'] # []
  • 自定义默认值

    1
    2
    3
    4
    pos = nltk.defaultdict(lambda:'N')
    pos['blog'] # N
    # 访问一个不存在的条目时,会自动添加字典
    post.items() # [('blog','N')]

递增的更新字典(略)

nltk.Index((''.join(sorted(w)), w) for w in words)

复杂的键和值

使用具有复杂的键和值的默认字典

研究一个词的可能标记范围,并对给定词本身和前一个词进行标记

看看这些信息如何被 POS 标注器使用

1
2
3
4
5
6
7
8
pos = nltk.defaultdict(lambda: nltk.defaultdict(int))
brown_news_tagged = brown.tagged_words(categories='news', tagset='universal')
for ((w1, t1), (w2, t2)) in nltk.bigrams(brown_news_tagged):
pos[(t1, w2)][t2] += 1
print(pos[('DET', 'right')])
"""
defaultdict(<class 'int'>, {'NOUN': 5, 'ADJ': 11})
"""

当right前面是限定词,应标注为ADJ

颠倒字典

原因:给定键查值很方便,给定值查键很麻烦(慢)

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
27
28
counts = nltk.defaultdict(int)
for word in nltk.corpus.gutenberg.words('milton-paradise.txt'):
counts[word] += 1
revers = [key for (key, value) in counts.items() if value == 32]
print(revers)
"""
['mortal', 'Against', 'Him', 'There', 'brought', 'King', 'virtue', 'every', 'been', 'thine']
"""

# 经常要进行反向查找,可建立一个映射值到键的字典
# 1. 每个key都有唯一个value值
pos = {'colorless': 'ADJ', 'ideas': 'N', 'sleep': 'V', 'furiously': 'ADV'}
pos2 = dict((value, key) for (key, value) in pos.items())
print('颠倒词典后通过value取值pos2["N"]:%s' % pos2['N'])
# 2. 有几个value相同
pos.update({'cats': 'N', 'scratch': 'V', 'peacefully': 'ADV', 'old': 'ADJ'})
pos2 = nltk.defaultdict(list)
for key, value in pos.items():
pos2[value].append(key)
print('颠倒词典(append)后通过value取值pos2["ADV"]:%s' % pos2['ADV'])
# nltk 索引支持进行相同的操作
pos2 = nltk.Index((value, key) for key, value in pos.items())
print('nltk 索引支持进行相同的操作取值pos2["ADV"]:%s' % pos2['ADV'])
"""
颠倒词典后通过value取值pos2["N"]:ideas
颠倒词典(append)后通过value取值pos2["ADV"]:['furiously', 'peacefully']
nltk 索引支持进行相同的操作取值pos2["ADV"]:['furiously', 'peacefully']
"""

5.4自动标注

1
2
3
4
5
6
7
8
9
10
11
import nltk
from nltk.corpus import brown

# 加载数据
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_tagged_words = brown.tagged_words(categories="news")
brown_sents = brown.sents(categories="news")
brown_words = brown.words(categories="news")

print(brown_tagged_sents[0:5])
print(brown_sents[0:5])

默认标注器

用最有可能的标记去标注新词,例子中是名词,这样
新词会被标注成名词,文本中大多数新词都是名词,
默认标注器可以帮助我们提高语言处理系统的稳定性

1
2
3
4
5
6
7
8
9
10
11
12
# 创建一个将所有词都标注成 NN 的标注器
raw = 'I do not like green eggs and ham, I do not like them Sam I am!'
tokens = nltk.word_tokenize(raw)
default_tagger = nltk.DefaultTagger('NN')
default_tagger_words = default_tagger.tag(tokens)
print("所有词都标注成 NN:\n%s" % default_tagger_words)
# 标注效果,不好,只标注正确了八分之一的标识符
print("标注效果:%s" % default_tagger.evaluate(brown_tagged_sents))
"""
[('I', 'NN'), ('do', 'NN'), ('not', 'NN'), ('like', 'NN'), ('green', 'NN'), ('eggs', 'NN'), ('and', 'NN'), ('ham', 'NN'), (',', 'NN'), ('I', 'NN'), ('do', 'NN'), ('not', 'NN'), ('like', 'NN'), ('them', 'NN'), ('Sam', 'NN'), ('I', 'NN'), ('am', 'NN'), ('!', 'NN')]
标注效果:0.13089484257215028
"""

正则表达式标注器 (自动化这里工作方法见第6.1节)

基于匹配模式分配标记给标识符,例如一般情况下认为
以ed结尾的词都是动词过去分词,
以’s结尾的词都是名词所有格

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
# 正则表达式标注器
# 基于匹配模式分配标记给标识符,例如一般情况下认为
# 以ed结尾的词都是动词过去分词,
# 以's结尾的词都是名词所有格
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)
]

regexp_tagger = nltk.RegexpTagger(patterns)
regexp_tagger_words = regexp_tagger.tag(brown_sents[3])
print("正则标注成 :\n%s" % regexp_tagger_words)
regexp_tagger.evaluate(brown_tagged_sents)
print("标注效果:%s" % regexp_tagger.evaluate(brown_tagged_sents))
"""
正则标注成 :
[('``', 'NN'), ('Only', 'NN'), ('a', 'NN'), ('relative', 'NN'), ('handful', 'NN'), ('of', 'NN'), ('such', 'NN'), ('reports', 'VBG'), ('was', 'VBG'), ('received', 'VBD'), ("''", 'NN'), (',', 'NN'), ('the', 'NN'), ('jury', 'NN'), ('said', 'NN'), (',', 'NN'), ('``', 'NN'), ('considering', 'VBG'), ('the', 'NN'), ('widespread', 'NN'), ('interest', 'NN'), ('in', 'NN'), ('the', 'NN'), ('election', 'NN'), (',', 'NN'), ('the', 'NN'), ('number', 'NN'), ('of', 'NN'), ('voters', 'VBG'), ('and', 'NN'), ('the', 'NN'), ('size', 'NN'), ('of', 'NN'), ('this', 'VBG'), ('city', 'NN'), ("''", 'NN'), ('.', 'NN')]
标注效果:0.16920261749905524
"""

查询标注器(NLTK Unigram Tagger)

找出 高频词,存储它们最有可能的标记,使用此信息作为”查找标注器”的模型

这里baseline_tagger.tag(sent)输出根据100个最频繁的词的标记正确

标注很大一部分数据,剩下的词许多应该被分配 None 标签,

但是实际运行后很多词已经分配了非 None 标签

不在100个最频繁的词之中,希望分配默认标记 NN ,即先查表,
如果不能指定标记就使用默认标注器(此过程称为回退)

可以指定一个标注器作为另一个标注器的参数,从而完成该操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查找标注器 =========================================================
fd = nltk.FreqDist(brown_words)
cfd = nltk.ConditionalFreqDist(brown_tagged_words)
most_freq_words = list(fd.keys())[:100]
likely_tags = dict((word, cfd[word].max()) for word in most_freq_words)
baseline_tagger = nltk.UnigramTagger(model=likely_tags)
print("查找标注器结果 :\n%s" % baseline_tagger)
print("标注效果:%s" % baseline_tagger.evaluate(brown_tagged_sents))

sent = brown_sents[3]
print(baseline_tagger.tag(sent))

baseline_tagger = nltk.UnigramTagger(model=likely_tags, backoff=nltk.DefaultTagger('NN'))
print("查找标注器结果 :\n%s" % baseline_tagger)
print("标注效果:%s" % baseline_tagger.evaluate(brown_tagged_sents))
"""
<UnigramTagger: size=100>
标注效果:0.3329355371243312
[('``', '``'), ('Only', 'RB'), ('a', 'AT'), ('relative', 'JJ'), ('handful', 'NN'), ('of', 'IN'), ('such', 'JJ'), ('reports', 'NNS'), ('was', 'BEDZ'), ('received', 'VBD'), ("''", "''"), (',', ','), ('the', 'AT'), ('jury', 'NN'), ('said', 'VBD'), (',', ','), ('``', '``'), ('considering', 'IN'), ('the', 'AT'), ('widespread', 'JJ'), ('interest', 'NN'), ('in', 'IN'), ('the', 'AT'), ('election', 'NN'), (',', ','), ('the', 'AT'), ('number', 'NN'), ('of', 'IN'), ('voters', 'NNS'), ('and', 'CC'), ('the', 'AT'), ('size', 'NN'), ('of', 'IN'), ('this', 'DT'), ('city', 'NN'), ("''", "''"), ('.', '.')]
查找标注器结果 :
<UnigramTagger: size=100>
标注效果:0.46063806511923944
"""

查找标注器的性能,使用不同大小的模型

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
27
28
29
import nltk
from nltk.corpus import brown


def performance(cfd, wordlist, brown_tagged_sents):
lt = dict((word, cfd[word].max()) for word in wordlist)
baseline_tagger = nltk.UnigramTagger(model=lt, backoff=nltk.DefaultTagger('NN'))
return baseline_tagger.evaluate(brown_tagged_sents)


def display():
import pylab
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_tagged_words = brown.tagged_words(categories="news")
# brown_sents = brown.sents(categories="news")
brown_words = brown.words(categories="news")

words_by_freq = list(nltk.FreqDist(brown_words))
cfd = nltk.ConditionalFreqDist(brown_tagged_words)
sizes = 2 ** pylab.arange(15)
perfs = [performance(cfd, words_by_freq[:size], brown_tagged_sents) for size in sizes]
pylab.plot(sizes, perfs, '-bo')
pylab.title('Lookup Tagger Performance with Varying Model Size')
pylab.xlabel('Model Size')
pylab.ylabel('Performance')
pylab.show()


display()

评估(11章讨论创建语料库的问题)

黄金标准测试数据

5.5 N-gram 标注

一元标注器(Unigram Tagging)

一元标注器利用一种简单的统计算法,对每个标识符分配最有可能的标记.

一元标注器的行为与查找标注器相似,建立一元标注器的技术,称为训练

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import nltk
from nltk.corpus import brown

# 加载数据
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories="news")

# 通过在初始化标注器时指定已标注的句子数据作为参数来训练一元标注器
# 训练过程会检查每个词的标记,将所有词的最可能标记存储在一个字典里面
# 这个字典存储在标注器的内部
unigram_tagger = nltk.UnigramTagger(brown_tagged_sents)
unigram_tagger_tag = unigram_tagger.tag(brown_sents[2007])
print(unigram_tagger_tag)
print(unigram_tagger.evaluate(brown_tagged_sents))
"""
[('Various', 'JJ'), ('of', 'IN'), ('the', 'AT'), ('apartments', 'NNS'), ('are', 'BER'), ('of', 'IN'), ('the', 'AT'), ('terrace', 'NN'), ('type', 'NN'), (',', ','), ('being', 'BEG'), ('on', 'IN'), ('the', 'AT'), ('ground', 'NN'), ('floor', 'NN'), ('so', 'QL'), ('that', 'CS'), ('entrance', 'NN'), ('is', 'BEZ'), ('direct', 'JJ'), ('.', '.')]
0.9349006503968017
"""

分离训练和测试数据

分割数据,90% 为训练数据,10%为测试数据

性能下降了,但是真是评估了模型的泛化能力

1
2
3
4
5
6
7
8
9
10
size = int(len(brown_tagged_sents) * 0.9)
print(size)
train_sents = brown_tagged_sents[:size]
test_sents = brown_tagged_sents[size:]
unigram_tagger = nltk.UnigramTagger(train_sents)
print(unigram_tagger.evaluate(test_sents))
"""
4160
0.8121200039868434
"""

一般的 N-gram 的标注

当基于 unigrams 处理语言处理任务时,可使用上下文中的项目.

标注时只考虑当前标识符,而不考虑其他上下文

给定一个模型,最好是为每个词标注其先验的最可能标记,

n-gram 标注器是 unigram 标注器的一般化,它的上下文是
当前词和它前面 n-1个标识符的词性标记

n-gram 标注器将挑选在给定上下文中最有可能的标记

图5-5 标注器的上下文 P(223)

  • 1-gram 标注器是一元标注器(unigram tagger)的另一个名称(用于标注的上下文是标识符本身)
  • 2-gram 标注器也称为二元标注器(bigram taggers)
  • 3-gram 标注器也成为三元标注器(trigram taggers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# NgramTagger 类,使用一个已标注的训练语料库来确定每个上下文中哪个词性标记最有可能
bigram_tagger = nltk.BigramTagger(train_sents)
bigram_tagger_tag = bigram_tagger.tag(brown_sents[2007])
print(bigram_tagger_tag)
unseen_sent = brown_sents[4203]
bigram_tagger_tag = bigram_tagger.tag(unseen_sent)
print(bigram_tagger_tag)
# 无法标注训练集中未看见过的词,也无法标注看见过但前面是None的词,所以准确度得分很低
print(bigram_tagger.evaluate(test_sents))
"""
[('Various', 'JJ'), ('of', 'IN'), ('the', 'AT'), ('apartments', 'NNS'), ('are', 'BER'), ('of', 'IN'), ('the', 'AT'), ('terrace', 'NN'), ('type', 'NN'), (',', ','), ('being', 'BEG'), ('on', 'IN'), ('the', 'AT'), ('ground', 'NN'), ('floor', 'NN'), ('so', 'CS'), ('that', 'CS'), ('entrance', 'NN'), ('is', 'BEZ'), ('direct', 'JJ'), ('.', '.')]
[('The', 'AT'), ('population', 'NN'), ('of', 'IN'), ('the', 'AT'), ('Congo', 'NP'), ('is', 'BEZ'), ('13.5', None), ('million', None), (',', None), ('divided', None), ('into', None), ('at', None), ('least', None), ('seven', None), ('major', None), ('``', None), ('culture', None), ('clusters', None), ("''", None), ('and', None), ('innumerable', None), ('tribes', None), ('speaking', None), ('400', None), ('separate', None), ('dialects', None), ('.', None)]
0.10206319146815508
"""

组合标注器

标注器初始化时指定回退标注器,从而训练时才能利用回退标注器

标注器与其回退标注器在上下文中分配一样的标记,
那么此标注器将丢弃训练的实例(保持尽可能小的标注器模型)

nltk.BigramTagger(sents,cutoff=2,backoff=t1)
将丢弃那些只出现一次或两次的上下文

1
2
3
4
5
# 组合标注器
t0 = nltk.DefaultTagger('NN')
t1 = nltk.UnigramTagger(train_sents, backoff=t0)
t2 = nltk.BigramTagger(train_sents, backoff=t1)
print(t2.evaluate(test_sents)) # 0.8452108043456593

标注生词

方法是回退到正则表达式标注器或默认标注器.(这些都无法利用上下文)

更好的处理生词或词汇表以外的项目:

基于上下文标注生词的方法是限制标注器的词汇表为最频繁的n个词,
将其他每个词归为特殊的词 UNK ,
训练时, unigram 标注器可能会将 UNK 标注为名词
而 n-gram 标注器会检测其他标记的上下文,
此时 UNK 可能会被标记为一个动词

存储标注器

1
2
3
4
5
6
7
8
9
10
11
12
13
import pickle


# 序列化
def dump(filename, data):
with open('%s.pkl' % filename, 'wb') as f:
pickle.dump(data, f)


# 反序列化
def load(filename):
with open(filename, 'rb') as f:
return pickle.load(f)

将标注器 t2 保存到文件 t2.pkl,

dump('t2', t2)

载入保存的标注器,并进行标注

1
2
3
4
5
6
7
8
9

tagger = load('t2.pkl')
text = """The board's action shows what free enterprise
is up against in our complex maze of regulatory laws ."""
tokens = text.split()
print(tagger.tag(tokens))
"""
[('The', 'AT'), ("board's", 'NN$'), ('action', 'NN'), ('shows', 'NNS'), ('what', 'WDT'), ('free', 'JJ'), ('enterprise', 'NN'), ('is', 'BEZ'), ('up', 'RP'), ('against', 'IN'), ('in', 'IN'), ('our', 'PP$'), ('complex', 'JJ'), ('maze', 'NN'), ('of', 'IN'), ('regulatory', 'NN'), ('laws', 'NNS'), ('.', '.')]
"""

性能限制

n-gram 标注器的上限是什么?

  1. 参考trigram标注器遇到多少词性歧义的情况
1
2
3
4
5
6
7
8
9
10
cfd = nltk.ConditionalFreqDist(
((x[1], y[1], z[0]), z[1])
for sent in brown_tagged_sents
for x, y, z in nltk.trigrams(sent)
)

ambiguous_context = [c for c in cfd.conditions() if len(cfd[c]) > 1]
print(sum(cfd[c].N() for c in ambiguous_context) / cfd.N())
# 0.049297702068029296
# 约1/20 的 trigrams是有歧义的
  1. 研究标注器的错误(查看混淆矩阵)
1
2
3
test_tags = [tag for sent in brown.sents(categories='editorial') for (word, tag) in t2.tag(sent)]
gold_tags = [tag for (word, tag) in brown.tagged_words(categories='editorial')]
print(nltk.ConfusionMatrix(gold_tags, test_tags))

基于以上分析,标记之间很难做出区分的部分可以被丢弃
(因为在一些较大的处理任务的上下文中并不重要)

跨句子边界标注

n-gram 标注器使用最近的标记作为当前词选择标记的指导,
当标记句子的第一个词时,trigram标注器使用前面两个标识符的词性标记
(通常是上一句的最后一个词和句尾标点),此时标识符这两个标记通常没有关系

解决此问题可以使用已标注句子的链表来训练、运行和评估标注器

1
2
3
# 句子层面的 N-gram 标注
print(t2.evaluate(test_sents))
# 0.8452108043456593

5.6 基于转换的标注

n-gram标注存在的潜在问题

  1. n-gram 表的大小(或语言模型),若将各种语言技术的标注器部署在移动计算设备上,在模型大小和性能之间取得平衡很重要.使用回退标注器的 n-gram 标注器可以存储 trigram 和 bigram 表(是一项巨大的稀疏阵列,可能有数亿条条目)
  2. 上下文,n-gram 标注器从前面的上下文中获得的唯一信息是标记,即使词本身可能是一个有用的信息源.n-gram 模型中以上下文中的词的其他特征为条件是不切实际的

Brill 标注

  1. 是一种归纳标注方法,性能好,使用的模型仅有 n-gram 标注器的很小一部分
  2. 是一种基于转换的学习,不计数观察结果,只编制一个转换修正规则链表
  3. 规则是语言学可解释的

Brill 标注器陆续将一个不良标注的文本转换成一个好的,

先使用 unigram 标注器标注,然后运用规则修正错误.

规则由模板产生(在上下文C中,替换T1为T2)

训练阶段,T1、T2和C的标注器猜测值创造出数以千计的候选规则.

每一条规则都根据其净收益打分:修正不正确标记的数目减去错误修正正确标记的数目

Brill 标注器的演示代码 ==有问题== # xxliu

1
2
import nltk
nltk.tag.brill.demo()

5.7 如何确定一个词的分类

一般情况下,语言学家使用形态学、句法和语义线索确定一个词的类别

形态学线索

一个词的内部结构有助于为这个词分类

  • -ness 是一个后缀,与形容词结合产生名词
  • -ment 与动词结合产生名词
  • -ing
    • 可以是动词的现在分词,表示正在进行还未结束
    • 也可以是从动派生的名词中,(动名词)

句法线索

一个词可能出现的典型的上下文语境
eg: 英语形容词的句法标准:它可以出现在一个名词前,或紧跟在词 be 或 very 后.根据这些测试,near 应该被归类为形容词

a.the near window

b.The end is (very) near.

语义线索

一个词的意思

eg:名词的定义是根据定义的:”一个人、地方或事物的名称”

新词

所有的语言都会产生新的词汇

名词被称为开放类

介词被认为是封闭类

词类成员随着时间的推移会组建发生改变

词性标记集中的形态学

普通标记集经常会”捕捉”一些构词信息,即一种词借助句法角色获得的形态标记信息

eg: go

a. Go away!

b. He sometimes goes to the cafe.

c. All the cakes have gone.

d. We went on the excursion.

表5-7 布朗标记集的一些构词区别 P(232)

动词细粒度标记意味着使用此标记集的自动标注器能有效开展有限数量的形态分析

大多数词性标注集都是用相同的基本类别,如名词、动词、形容词和介词.

然而,标记集之间的区别不仅在于他们如何细致的 将词分类,
更在于它们如何界定其类别

这种标记集的变化是不可避免的,因为词性标记以不同的方式应用于不同的任务

最后更新: 2019年05月09日 12:37

原始链接: https://ice-melt.github.io/2019/04/18/Python_NLP_05/

× 您的支持是我原创的动力
打赏二维码