10 练习
- ☼ 网上搜索“spoof newspaper headlines”,找到这种宝贝:British Left Waffles on Falkland Islands 和 Juvenile Court to Try Shooting Defendant。手工标注这些头条,看看词性标记的知识是否可以消除歧义。
- ☼ 和别人一起,轮流挑选一个既可以是名词也可以是动词的词(如 contest);让对方预测哪一个可能是布朗语料库中频率最高的;检查对方的预测,为几个回合打分。
- ☼ 分词和标注下面的句子:They wind back the clock, while we chase after the wind。涉及哪些不同的发音和词类?
- ☼ 回顾3.1中的映射。讨论你能想到的映射的其他的例子。它们从什么类型的信息映射到什么类型的信息?
- ☼ 在交互模式下使用 Python 解释器,实验本章中字典的例子。创建一个字典
d
,添加一些条目。如果你尝试访问一个不存在的条目会发生什么,如d['xyz']
? - ☼ 尝试从字典
d
删除一个元素,使用语法del d['abc']
。检查被删除的项目。 - ☼ 创建两个字典,
d1
和d2
,为每个添加一些条目。现在发出命令d1.update(d2)
。这做了什么?它可能是有什么用? - ☼ 创建一个字典
e
,表示你选择的一些词的一个单独的词汇条目。定义键如headword
、part-of-speech
、sense
和example
,分配给它们适当的值。 - ☼ 自己验证 go 和 went 在分布上的限制,也就是说,它们不能自由地在7中的(3d)演示的那种上下文中互换。
- ☼ 训练一个一元标注器,在一些新的文本上运行。观察有些词没有分配到标记。为什么没有?
- ☼ 了解词缀标注器(输入
help(nltk.AffixTagger)
)。训练一个词缀标注器,在一些新的文本上运行。设置不同的词缀长度和最小词长做实验。讨论你的发现。 - ☼ 训练一个没有回退标注器的二元标注器,在一些训练数据上运行。下一步,在一些新的数据运行它。标注器的准确性会发生什么?为什么呢?
- ☼ 我们可以使用字典指定由一个格式化字符串替换的值。阅读关于格式化字符串的 Python 库文档
http://docs.python.org/lib/typesseq-strings.html
,使用这种方法以两种不同的格式显示今天的日期。 - ◑ 使用
sorted()
和set()
获得布朗语料库使用的标记的排序的列表,删除重复。 - ◑ 写程序处理布朗语料库,找到以下问题的答案:
- 哪些名词常以它们复数形式而不是它们的单数形式出现?(只考虑常规的复数形式,-s 后缀形式的)。
- 哪个词的不同标记数目最多。它们是什么,它们代表什么?
- 按频率递减的顺序列出标记。前 20 个最频繁的标记代表什么?
- 名词后面最常见的是哪些标记?这些标记代表什么?
- ◑ 探索有关查找标注器的以下问题:
- 回退标注器被省略时,模型大小变化,标注器的准确性会发生什么?
- 思考4.2的曲线;为查找标注器推荐一个平衡内存和准确性的好的规模。你能想出在什么情况下应该尽量减少内存使用,什么情况下性能最大化而不必考虑内存使用?
- ◑ 查找标注器的准确性上限是什么,假设其表的大小没有限制?(提示:写一个程序算出被分配了最有可能的标记的词的词符的平均百分比。)
- ◑ 生成已标注数据的一些统计数据,回答下列问题:
- 总是被分配相同词性的词类的比例是多少?
- 多少词是有歧义的,从某种意义上说,它们至少和两个标记一起出现?
- 布朗语料库中这些有歧义的词的 词符 的百分比是多少?
- ◑
evaluate()
方法算出一个文本上运行的标注器的精度。例如,如果提供的已标注文本是[('the', 'DT'), ('dog', 'NN')]
,标注器产生的输出是[('the', 'NN'), ('dog', 'NN')]
,那么得分为0.5
。让我们尝试找出评价方法是如何工作的:- 一个标注器
t
将一个词汇列表作为输入,产生一个已标注词列表作为输出。然而,t.evaluate()
只以一个正确标注的文本作为唯一的参数。执行标注之前必须对输入做些什么? - 一旦标注器创建了新标注的文本,
evaluate()
方法可能如何比较它与原来标注的文本,计算准确性得分? - 现在,检查源代码来看看这个方法是如何实现的。检查
nltk.tag.api.__file__
找到源代码的位置,使用编辑器打开这个文件(一定要使用文件api.py
,而不是编译过的二进制文件api.pyc
)。
- 一个标注器
- ◑ 编写代码,搜索布朗语料库,根据标记查找特定的词和短语,回答下列问题:
- 产生一个标注为
MD
的不同的词的按字母顺序排序的列表。 - 识别可能是复数名词或第三人称单数动词的词(如 deals, flies)。
- 识别三个词的介词短语形式 IN + DET + NN(如 in the lab)。
- 男性与女性代词的比例是多少?
- 产生一个标注为
- ◑ 在3.1中我们看到动词 adore, love, like, prefer 及前面的限定符 absolutely 和 definitely 的频率计数的表格。探讨这四个动词前出现的所有限定符。
- ◑ 我们定义可以用来做生词的回退标注器的
regexp_tagger
。这个标注器只检查基数词。通过特定的前缀或后缀字符串进行测试,它应该能够猜测其他标记。例如,我们可以标注所有-s 结尾的词为复数名词。定义一个正则表达式标注器(使用RegexpTagger()
),测试至少 5 个单词拼写的其他模式。(使用内联文档解释规则。) - ◑ 考虑上一练习中开发的正则表达式标注器。使用它的
accuracy()
方法评估标注器,尝试想办法提高其性能。讨论你的发现。客观的评估如何帮助开发过程? - ◑ 数据稀疏问题有多严重?调查 n-gram 标注器当 n 从 1 增加到 6 时的准确性。为准确性得分制表。估计这些标注器需要的训练数据,假设词汇量大小为 10<sup>5</sup>而标记集的大小为 10<sup>2</sup>。
- ◑ 获取另一种语言的一些已标注数据,在其上测试和评估各种标注器。如果这种语言是形态复杂的,或者有词类的任何字形线索(如),可以考虑为它开发一个正则表达式标注器(排在一元标注器之后,默认标注器之前)。对比同样的运行在英文数据上的标注器,你的标注器的准确性如何?讨论你在运用这些方法到这种语言时遇到的问题。
- ◑ 4.1绘制曲线显示查找标注器的性能随模型的大小增加的变化。绘制当训练数据量变化时一元标注器的性能曲线。
- ◑ 检查5中定义的二元标注器
t2
的混淆矩阵,确定简化的一套或多套标记。定义字典做映射,在简化的数据上评估标注器。 - ◑ 使用简化的标记集测试标注器(或制作一个你自己的,通过丢弃每个标记名中除第一个字母外所有的字母)。这种标注器需要做的区分更少,但由它获得的信息也更少。讨论你的发现。
- ◑ 回顾一个二元标注器训练过程中遇到生词,标注句子的其余部分为
None
的例子。一个二元标注器可能只处理了句子的一部分就失败了,即使句子中没有包含生词(即使句子在训练过程中使用过)。在什么情况下会出现这种情况呢?你可以写一个程序,找到一些这方面的例子吗? - ◑ 预处理布朗新闻数据,替换低频词为 UNK,但留下标记不变。在这些数据上训练和评估一个二元标注器。这样有多少帮助?一元标注器和默认标注器的贡献是什么?
- ◑ 修改4.1中的程序,通过将
pylab.plot()
替换为pylab.semilogx()
,在 x 轴上使用对数刻度。关于结果图形的形状,你注意到了什么?梯度告诉你什么呢? - ◑ 使用
help(nltk.tag.brill.demo)
阅读 Brill 标注器演示函数的文档。通过设置不同的参数值试验这个标注器。是否有任何训练时间(语料库大小)和性能之间的权衡? - ◑ 写代码构建一个集合的字典的字典。用它来存储一套可以跟在具有给定词性标记的给定词后面的词性标记,例如 word<sub>i</sub> → tag<sub>i</sub> → tag<sub>i+1</sub>。
- ★ 布朗语料库中有 264 个不同的词有 3 种可能的标签。
- 打印一个表格,一列中是整数 1..10,另一列是语料库中有 1..10 个不同标记的不同词的数目。
- 对有不同的标记数量最多的词,输出语料库中包含这个词的句子,每个可能的标记一个。
- ★ 写一个程序,按照词 must 后面的词的标记为它的上下文分类。这样可以区分 must 的“必须”和“应该”两种词意上的用法吗?
- ★ 创建一个正则表达式标注器和各种一元以及 n-gram 标注器,包括回退,在布朗语料库上训练它们。
- 创建这些标注器的 3 种不同组合。测试每个组合标注器的准确性。哪种组合效果最好?
- 尝试改变训练语料的规模。它是如何影响你的结果的?
- ★ 我们标注生词的方法一直要考虑这个词的字母(使用
RegexpTagger()
),或完全忽略这个词,将它标注为一个名词(使用nltk.DefaultTagger()
)。这些方法对于有新词却不是名词的文本不会很好。思考句子 I like to blog on Kim’s blog。如果 blog 是一个新词,那么查看前面的标记(TO
和`NP 即我们需要一个对前面的标记敏感的默认标注器。- 创建一种新的一元标注器,查看前一个词的标记,而忽略当前词。(做到这一点的最好办法是修改
UnigramTagger()
的源代码,需要 Python 中的面向对象编程的知识。 - 将这个标注器加入到回退标注器序列(包括普通的三元和二元标注器),放在常用默认标注器的前面。
- 评价这个新的一元标注器的贡献。
- 创建一种新的一元标注器,查看前一个词的标记,而忽略当前词。(做到这一点的最好办法是修改
- ★ 思考5中的代码,它确定一个三元标注器的准确性上限。回顾 Abney 的关于精确标注的不可能性的讨论(Church, Young, & Bloothooft, 1996)。解释为什么正确标注这些例子需要获取词和标记以外的其他种类的信息。你如何估计这个问题的规模?
- ★ 使用
nltk.probability
中的一些估计技术,例如 Lidstone 或 Laplace 估计,开发一种统计标注器,它在训练中没有遇到而测试中遇到的上下文中表现优于 n-gram 回退标注器。 - ★ 检查 Brill 标注器创建的诊断文件
rules.out
和errors.out
。通过访问源代码(http://www.nltk.org/code
)获得演示代码,创建你自己版本的 Brill 标注器。并根据你从检查rules.out
了解到的,删除一些规则模板。增加一些新的规则模板,这些模板使用那些可能有助于纠正你在errors.out
看到的错误的上下文。 - ★ 开发一个 n-gram 回退标注器,允许在标注器初始化时指定“anti-n-grams”,如
["the", "the"]
。一个 anti-n-grams 被分配一个数字 0,被用来防止这个 n-gram 回退(如避免估计 P(the | the)而只做 P(the))。 - ★ 使用布朗语料库开发标注器时,调查三种不同的方式来定义训练和测试数据之间的分割:genre (
category
)、source (fileid
)和句子。比较它们的相对性能,并讨论哪种方法最合理。(你可能要使用 n-交叉验证,在3中讨论的,以提高评估的准确性。) - ★ 开发你自己的
NgramTagger
,从 NLTK 中的类继承,封装本章中所述的已标注的训练和测试数据的词汇表缩减方法。确保一元和默认回退标注器有机会获得全部词汇。
关于本文档…
UPDATED FOR NLTK 3.0. 本章来自于 Natural Language Processing with Python,Steven Bird, Ewan Klein 和Edward Loper,Copyright © 2014 作者所有。本章依据 Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License [http://creativecommons.org/licenses/by-nc-nd/3.0/us/] 条款,与 自然语言工具包 [http://nltk.org/
] 3.0 版一起发行。
本文档构建于星期三 2015 年 7 月 1 日 12:30:05 AEST