提交 88a8a89b 编写于 作者: W wizardforcel

2020-12-29 14:11:21

上级 1f32867d
......@@ -6,7 +6,7 @@
这本书提供自然语言处理领域非常方便的入门指南。它可以用来自学,也可以作为自然语言处理或计算语言学课程的教科书,或是人工智能、文本挖掘、语料库语言学课程的补充读物。本书的实践性很强,包括几百个实际可用的例子和分级练习。
本书基于 Python 编程语言及其上的一个名为*自然语言工具包*(Natural Language Toolkit ,简称 NLTK)的开源库。NLTK 包含大量的软件、数据和文档,所有这些都可以从`http://nltk.org/` 免费下载。NLTK 的发行版本支持 Windows、Macintosh 和 Unix 平台。我们强烈建议你下载 Python 和 NLTk,与我们一起尝试书中的例子和练习。
本书基于 Python 编程语言及其上的一个名为*自然语言工具包*(Natural Language Toolkit ,简称 NLTK)的开源库。NLTK 包含大量的软件、数据和文档,所有这些都可以从`http://nltk.org/`免费下载。NLTK 的发行版本支持 Windows、Macintosh 和 Unix 平台。我们强烈建议你下载 Python 和 NLTk,与我们一起尝试书中的例子和练习。
## 读者
......@@ -21,41 +21,41 @@ NLP 是科学、经济、社会和文化的一个重要因素。NLP 正在迅速
... print(word)
```
这段程序演示了 Python 的一些主要特征。首先,使用空格*缩进*代码,从而使`if`后面的代码都在前面一行`for`语句的范围之内;这保证了检查单词是否以`ing`结尾的测试对所有单词都进行。第二,Python 是*面向对象*语言;每一个变量都是包含特定属性和方法的对象。例如,变量`line` 的值不仅仅是一个字符串序列。它是一个`string`对象,包含一个用来把字符串分割成词的`split()` 方法(或叫操作)。我们在对象名称后面写上一个点再写上方法名称就可以调用对象的一个方法,例如`line.split()`。第三,方法的*参数*写在括号内。例如,上面的例子中的`word.endswith('ing')`具有一个参数`'ing'` 表示我们需要找的是`ing`结尾的词而不是别的结尾的词。最后也是最重要的,Python 的可读性如此之强以至于可以相当容易的猜出程序的功能,即使你以前从未写过一行代码。
这段程序演示了 Python 的一些主要特征。首先,使用空格*缩进*代码,从而使`if`后面的代码都在前面一行`for`语句的范围之内;这保证了检查单词是否以`ing`结尾的测试对所有单词都进行。第二,Python 是*面向对象*语言;每一个变量都是包含特定属性和方法的对象。例如,变量`line`的值不仅仅是一个字符串序列。它是一个`string`对象,包含一个用来把字符串分割成词的`split()`方法(或叫操作)。我们在对象名称后面写上一个点再写上方法名称就可以调用对象的一个方法,例如`line.split()`。第三,方法的*参数*写在括号内。例如,上面的例子中的`word.endswith('ing')`具有一个参数`'ing'`表示我们需要找的是`ing`结尾的词而不是别的结尾的词。最后也是最重要的,Python 的可读性如此之强以至于可以相当容易的猜出程序的功能,即使你以前从未写过一行代码。
我们选择 Python 是因为它的学习曲线比较平缓,文法和语义都很清晰,具有良好的处理字符串的功能。作为解释性语言,Python 便于交互式编程。作为面向对象语言,Python 允许数据和方法被方便的封装和重用。作为动态语言,Python 允许属性等到程序运行时才被添加到对象,允许变量自动类型转换,提高开发效率。Python 自带强大的标准库,包括图形编程、数值处理和网络连接等组件。
Python 在世界各地的工业、科研、教育领域应用广泛。它因为提高了软件的生产效率、质量和可维护性而备受称赞。`http://python.org/about/success/` 中列举了许多成功使用 Python 的故事。
Python 在世界各地的工业、科研、教育领域应用广泛。它因为提高了软件的生产效率、质量和可维护性而备受称赞。`http://python.org/about/success/`中列举了许多成功使用 Python 的故事。
NLTK 定义了一个使用 Python 进行 NLP 编程的基础工具。它提供重新表示自然语言处理相关数据的基本类,词性标注、文法分析、文本分类等任务的标准接口以及这些任务的标准实现,可以组合起来解决复杂的问题。
NLTK 自带大量文档。作为本书的补充,`http://nltk.org/` 网站提供的 API 文档涵盖工具包中每一个模块、类和函数,详细说明了各种参数,还给出了用法示例。
NLTK 自带大量文档。作为本书的补充,`http://nltk.org/`网站提供的 API 文档涵盖工具包中每一个模块、类和函数,详细说明了各种参数,还给出了用法示例。
## Python 3 和 NLTK 3
本书的这个版本已更新并支持 Python 3 和 NLTK 3。Python 3 包括一些重大的变化︰
* `print` 语句现在是函数,因此需要括号;
* `print`语句现在是函数,因此需要括号;
* 许多函数现在返回迭代器而不是列表 (以节省内存使用);
* 整数除法返回一个浮点数
* 所有文本现在都是 Unicode 编码
* 字符串的格式化使用`format` 方法
* 字符串的格式化使用`format`方法
这些变化的更多细节请参见`https://docs.python.org/dev/whatsnew/3.0.html`.。有一个`2to3.py` 工具可以将 Python 2 代码转换为 Python 3;关详细信息请参阅`https://docs.python.org/2/library/2to3.html`
这些变化的更多细节请参见`https://docs.python.org/dev/whatsnew/3.0.html`.。有一个`2to3.py`工具可以将 Python 2 代码转换为 Python 3;关详细信息请参阅`https://docs.python.org/2/library/2to3.html`
NLTK 同样很多地方都有更改︰
* 许多类型使用`fromstring()` 方法从字符串初始化
* 许多类型使用`fromstring()`方法从字符串初始化
* 许多函数现在返回迭代器而不是列表
* `ContextFreeGrammar` 现在叫做`CFG``WeightedGrammar` 现在叫做`PCFG`
* `batch_tokenize()` 现在叫做`tokenize_sents()`;对应的标记器, 解析器和分类器都有变化
* `ContextFreeGrammar`现在叫做`CFG``WeightedGrammar`现在叫做`PCFG`
* `batch_tokenize()`现在叫做`tokenize_sents()`;对应的标记器, 解析器和分类器都有变化
* 有些实现已删除以支持外部包,或因为不能充分维护
更详细的变更列表请参见`https://github.com/nltk/nltk/wiki/Porting-your-code-to-NLTK-3.0`
## 软件安装需求
为了充分利用好本书,你应该安装一些免费的软件包。`http://nltk.org/` 上有这些软件包当前的下载链接和安装说明。
为了充分利用好本书,你应该安装一些免费的软件包。`http://nltk.org/`上有这些软件包当前的下载链接和安装说明。
| Python: | 本书中例子假定你正在使用 Python 3.2 或更高版本。(注,NLTK 3.0 也适用于 Python 2.6 和 2.7)。 |
| --- | --- |
......@@ -163,7 +163,7 @@ NLTK 设计中的四个主要目标:
## 致谢
作者感激为本书早期手稿提供反馈意见的人,他们是:Doug Arnold, Michaela Atterer, Greg Aumann, Kenneth Beesley, Steven Bethard, Ondrej Bojar, Chris Cieri, Robin Cooper, Grev Corbett, James Curran, Dan Garrette, Jean Mark Gawron, Doug Hellmann, Nitin Indurkhya, Mark Liberman, Peter Ljunglöf, Stefan Müller, Robin Munn, Joel Nothman, Adam Przepiorkowski, Brandon Rhodes, Stuart Robinson, Jussi Salmela, Kyle Schlansker, Rob Speer 和 Richard Sproat。感谢许许多多的学生和同事,他们关于课堂材料的意见演化成本书的这些章节,其中包括巴西,印度和美国的 NLP 与语言学暑期学校的参加者。没有`nltk-dev` 开发社区的成员们的努力这本书也不会存在,他们为建设和壮大 NLTK 无私奉献他们的时间和专业知识,他们的名字都记录在 NLTK 网站上。
作者感激为本书早期手稿提供反馈意见的人,他们是:Doug Arnold, Michaela Atterer, Greg Aumann, Kenneth Beesley, Steven Bethard, Ondrej Bojar, Chris Cieri, Robin Cooper, Grev Corbett, James Curran, Dan Garrette, Jean Mark Gawron, Doug Hellmann, Nitin Indurkhya, Mark Liberman, Peter Ljunglöf, Stefan Müller, Robin Munn, Joel Nothman, Adam Przepiorkowski, Brandon Rhodes, Stuart Robinson, Jussi Salmela, Kyle Schlansker, Rob Speer 和 Richard Sproat。感谢许许多多的学生和同事,他们关于课堂材料的意见演化成本书的这些章节,其中包括巴西,印度和美国的 NLP 与语言学暑期学校的参加者。没有`nltk-dev`开发社区的成员们的努力这本书也不会存在,他们为建设和壮大 NLTK 无私奉献他们的时间和专业知识,他们的名字都记录在 NLTK 网站上。
非常感谢美国国家科学基金会、语言数据联盟、Edward Clarence Dyason 奖学金、宾州大学、爱丁堡大学和墨尔本大学对我们在本书相关的工作上的支持。
......@@ -179,7 +179,7 @@ NLTK 设计中的四个主要目标:
**Ewan Klein**是英国爱丁堡大学信息学院语言技术教授。于 1978 年在剑桥大学完成形式语义学博士学位。在苏塞克斯和纽卡斯尔大学工作多年后,参加了在爱丁堡的教学岗位。他于 1993 年参与了爱丁堡语言科技集团的建立,并一直与之密切联系。从 2000 到 2002,他离开大学作为圣克拉拉的埃迪法公司的总部在爱丁堡的自然语言的研究小组的研发经理,负责处理口语对话。Ewan 是计算语言学协会欧洲分会(European Chapter of the Association for Computational Linguistics)前任主席,并且是人类语言技术(ELSNET)欧洲卓越网络的创始成员和协调员。
**Edward Loper** 最近完成了宾夕法尼亚大学自然语言处理的机器学习博士学位。Edward 是 Steven 在 2000 年秋季计算语言学研究生课程的学生,也是教师助手和 NLTK 开发的成员。除了 NLTK,他帮助开发了用于文档化和测试 Python 软件的两个包:`epydoc` `doctest`
**Edward Loper** 最近完成了宾夕法尼亚大学自然语言处理的机器学习博士学位。Edward 是 Steven 在 2000 年秋季计算语言学研究生课程的学生,也是教师助手和 NLTK 开发的成员。除了 NLTK,他帮助开发了用于文档化和测试 Python 软件的两个包:`epydoc``doctest`
## 版税
......
此差异已折叠。
......@@ -372,7 +372,7 @@ sleep: wake
Python 的 ElementTree 模块提供了一种方便的方式访问存储在 XML 文件中的数据。ElementTree 是 Python 标准库(自从 Python 2.5)的一部分,也作为 NLTK 的一部分提供,以防你在使用 Python 2.4。
我们将使用 XML 格式的莎士比亚戏剧集来说明 ElementTree 的使用方法。让我们加载 XML 文件并检查原始数据,首先在文件的顶部[](./ch11.html#top-of-file),在那里我们看到一些 XML 头和一个名为`play.dtd`的模式,接着是根元素 `PLAY`。我们从 Act 1[](./ch11.html#start-act-one)再次获得数据。(输出中省略了一些空白行。)
我们将使用 XML 格式的莎士比亚戏剧集来说明 ElementTree 的使用方法。让我们加载 XML 文件并检查原始数据,首先在文件的顶部[](./ch11.html#top-of-file),在那里我们看到一些 XML 头和一个名为`play.dtd`的模式,接着是根元素`PLAY`。我们从 Act 1[](./ch11.html#start-act-one)再次获得数据。(输出中省略了一些空白行。)
```py
>>> merchant_file = nltk.data.find('corpora/shakespeare/merchant.xml')
......
......@@ -170,7 +170,7 @@ can: 94 could: 87 may: 93 might: 38 must: 53 will: 389
注意
我们需要包包含`结束 = ' '` 以让 print 函数将其输出放在单独的一行。
我们需要包包含`结束 = ' '`以让 print 函数将其输出放在单独的一行。
注意
......@@ -253,7 +253,7 @@ science_fiction 16 49 4 12 8 16
请注意,每个文本的年代都出现在它的文件名中。要从文件名中获得年代,我们使用`fileid[:4]`提取前四个字符。
让我们来看看词汇 America 和 citizen 随时间推移的使用情况。下面的代码使用`w.lower()` [](./ch02.html#lowercase-startswith)将就职演说语料库中的词汇转换成小写,然后用`startswith()` [](./ch02.html#lowercase-startswith)检查它们是否以“目标”词汇`america` `citizen`开始。因此,它会计算如 American's 和 Citizens 等词。我们将在第 2 节学习条件频率分布,现在只考虑输出,如图[1.1](./ch02.html#fig-inaugural2)所示。
让我们来看看词汇 America 和 citizen 随时间推移的使用情况。下面的代码使用`w.lower()` [](./ch02.html#lowercase-startswith)将就职演说语料库中的词汇转换成小写,然后用`startswith()` [](./ch02.html#lowercase-startswith)检查它们是否以“目标”词汇`america``citizen`开始。因此,它会计算如 American's 和 Citizens 等词。我们将在第 2 节学习条件频率分布,现在只考虑输出,如图[1.1](./ch02.html#fig-inaugural2)所示。
```py
>>> cfd = nltk.ConditionalFreqDist(
......@@ -267,7 +267,7 @@ science_fiction 16 49 4 12 8 16
![Images/4cdc400cf76b0354304e01aeb894877b.jpg](Images/4cdc400cf76b0354304e01aeb894877b.jpg)
图 1.1:条件频率分布图:计数就职演说语料库中所有以`america` `citizen`开始的词;每个演讲单独计数;这样就能观察出随时间变化用法上的演变趋势;计数没有与文档长度进行归一化处理。
图 1.1:条件频率分布图:计数就职演说语料库中所有以`america``citizen`开始的词;每个演讲单独计数;这样就能观察出随时间变化用法上的演变趋势;计数没有与文档长度进行归一化处理。
## 1.6 标注文本语料库
......@@ -398,7 +398,7 @@ NLTK 中定义的基本语料库函数:使用`help(nltk.corpus.reader)`可以
## 2.2 按文体计数词汇
[1](./ch02.html#sec-extracting-text-from-corpora)中,我们看到一个条件频率分布,其中条件为布朗语料库的每一节,并对每节计数词汇。`FreqDist()`以一个简单的列表作为输入,`ConditionalFreqDist()` 以一个配对列表作为输入。
[1](./ch02.html#sec-extracting-text-from-corpora)中,我们看到一个条件频率分布,其中条件为布朗语料库的每一节,并对每节计数词汇。`FreqDist()`以一个简单的列表作为输入,`ConditionalFreqDist()`以一个配对列表作为输入。
```py
>>> from nltk.corpus import brown
......@@ -536,7 +536,7 @@ print('Monty Python')
你也可以输入`from monty import *`,它将做同样的事情。
从现在起,你可以选择使用交互式解释器或文本编辑器来创建你的程序。使用解释器测试你的想法往往比较方便,修改一行代码直到达到你期望的效果。测试好之后,你就可以将代码粘贴到文本编辑器(去除所有`>>>` `...`提示符),继续扩展它。给文件一个小而准确的名字,使用所有的小写字母,用下划线分割词汇,使用`.py`文件名后缀,例如`monty_python.py`
从现在起,你可以选择使用交互式解释器或文本编辑器来创建你的程序。使用解释器测试你的想法往往比较方便,修改一行代码直到达到你期望的效果。测试好之后,你就可以将代码粘贴到文本编辑器(去除所有`>>>``...`提示符),继续扩展它。给文件一个小而准确的名字,使用所有的小写字母,用下划线分割词汇,使用`.py`文件名后缀,例如`monty_python.py`
注意
......@@ -863,7 +863,7 @@ KeyError: 'blog'
'few', 'other', 'one', 'two', 'three', 'four', 'five', 'big', 'long', 'wide', ...]
```
我们可以通过在`entries()` 方法中指定一个语言列表来访问多语言中的同源词。更进一步,我们可以把它转换成一个简单的词典(我们将在[3](./ch05.html#sec-dictionaries)学到`dict()`函数)。
我们可以通过在`entries()`方法中指定一个语言列表来访问多语言中的同源词。更进一步,我们可以把它转换成一个简单的词典(我们将在[3](./ch05.html#sec-dictionaries)学到`dict()`函数)。
```py
>>> fr2en = swadesh.entries(['fr', 'en'])
......@@ -1190,7 +1190,7 @@ WordNet 同义词集的集合上定义的相似度能够包括上面的概念。
用于创建标注的文本语料库的好工具叫做 Brat,可从`http://brat.nlplab.org/`访问。
这些语料库和许多其他语言资源使用 OLAC 元数据格式存档,可以通过 `http://www.language-archives.org/`上的 OLAC 主页搜索到。Corpora List 是一个讨论语料库内容的邮件列表,你可以通过搜索列表档案来找到资源或发布资源到列表中。*Ethnologue* 是最完整的世界上的语言的清单,`http://www.ethnologue.com/`。7000 种语言中只有几十中有大量适合 NLP 使用的数字资源。
这些语料库和许多其他语言资源使用 OLAC 元数据格式存档,可以通过`http://www.language-archives.org/`上的 OLAC 主页搜索到。Corpora List 是一个讨论语料库内容的邮件列表,你可以通过搜索列表档案来找到资源或发布资源到列表中。*Ethnologue* 是最完整的世界上的语言的清单,`http://www.ethnologue.com/`。7000 种语言中只有几十中有大量适合 NLP 使用的数字资源。
本章触及语料库语言学领域。在这一领域的其他有用的书籍包括[(Biber, Conrad, & Reppen, 1998)](./bibliography.html#biber1998), [(McEnery, 2006)](./bibliography.html#mcenery2006), [(Meyer, 2002)](./bibliography.html#meyer2002), [(Sampson & McCarthy, 2005)](./bibliography.html#sampson2005), [(Scott & Tribble, 2006)](./bibliography.html#scott2006)。在语言学中海量数据分析的深入阅读材料有:[(Baayen, 2008)](./bibliography.html#baayen2008), [(Gries, 2009)](./bibliography.html#gries2009), [(Woods, Fletcher, & Hughes, 1986)](./bibliography.html#woods1986)
......
......@@ -110,7 +110,7 @@ Project Gutenberg; Dmitri Prokofitch; Andrey Semyonovitch; Hay Market
你可以输入`print(html)`来查看 HTML 的全部内容,包括 meta 元标签、图像标签、map 标签、JavaScript、表单和表格。
要得到 HTML 的文本,我们将使用一个名为 *BeautifulSoup* 的 Python 库,可从 `http://www.crummy.com/software/BeautifulSoup/` 访问︰
要得到 HTML 的文本,我们将使用一个名为 *BeautifulSoup* 的 Python 库,可从`http://www.crummy.com/software/BeautifulSoup/`访问︰
```py
>>> from bs4 import BeautifulSoup
......@@ -584,7 +584,7 @@ Unicode 支持超过一百万种字符。每个字符分配一个编号,称为
>>> path = nltk.data.find('corpora/unicode_samples/polish-lat2.txt')
```
Python 的`open()`函数可以读取编码的数据为 Unicode 字符串,并写出 Unicode 字符串的编码形式。它采用一个参数来指定正在读取或写入的文件的编码。因此,让我们使用编码 `'latin2'`打开我们波兰语文件,并检查该文件的内容︰
Python 的`open()`函数可以读取编码的数据为 Unicode 字符串,并写出 Unicode 字符串的编码形式。它采用一个参数来指定正在读取或写入的文件的编码。因此,让我们使用编码`'latin2'`打开我们波兰语文件,并检查该文件的内容︰
```py
>>> f = open(path, encoding='latin2')
......@@ -599,7 +599,7 @@ Jagiellońskiej w Krakowie, obejmują ponad 500 tys. zabytkowych
archiwaliów, m.in. manuskrypty Goethego, Mozarta, Beethovena, Bacha.
```
如果这不能在你的终端正确显示,或者我们想要看到字符的底层数值(或"代码点"),那么我们可以将所有的非 ASCII 字符转换成它们两位数`\x`*XX* 和四位数 `\u`*XXXX* 表示法︰
如果这不能在你的终端正确显示,或者我们想要看到字符的底层数值(或"代码点"),那么我们可以将所有的非 ASCII 字符转换成它们两位数`\x`*XX* 和四位数`\u`*XXXX* 表示法︰
```py
>>> f = open(path, encoding='latin2')
......@@ -623,7 +623,7 @@ b'archiwali\\xf3w, m.in. manuskrypty Goethego, Mozarta, Beethovena, Bacha.'
324
```
324 的 4 位十六进制数字的形式是 0144(输入 `hex(324)` 可以发现这点),我们可以定义一个具有适当转义序列的字符串。
324 的 4 位十六进制数字的形式是 0144(输入`hex(324)`可以发现这点),我们可以定义一个具有适当转义序列的字符串。
```py
>>> nacute = '\u0144'
......@@ -666,7 +666,7 @@ b'\xc5\x82' U+0142 LATIN SMALL LETTER L WITH STROKE
另外,根据你的系统的具体情况,你可能需要用`'latin2'`替换示例中的编码`'utf8'`
下一个例子展示 Python 字符串函数和`re`模块是如何能够与 Unicode 字符一起工作的。(我们会在下面一节中仔细看看`re` 模块。`\w`匹配一个"单词字符",参见[3.4](./ch03.html#tab-re-symbols))。
下一个例子展示 Python 字符串函数和`re`模块是如何能够与 Unicode 字符一起工作的。(我们会在下面一节中仔细看看`re`模块。`\w`匹配一个"单词字符",参见[3.4](./ch03.html#tab-re-symbols))。
```py
>>> line.find('zosta\u0142y')
......@@ -795,7 +795,7 @@ T9 系统用于在手机上输入文本(见[3.5](./ch03.html#fig-t9)))。两
注意
**轮到你来:** 研究前面的例子,在你继续阅读之前尝试弄清楚`\`, `{}`, `()``|` 这些符号的功能。
**轮到你来:** 研究前面的例子,在你继续阅读之前尝试弄清楚`\`, `{}`, `()``|`这些符号的功能。
你可能已经知道反斜杠表示其后面的字母不再有特殊的含义而是按照字面的表示匹配词中特定的字符。因此,虽然`.`很特别,但是`\.`只匹配一个句号。大括号表达式,如`{3,5}`, 表示前面的项目重复指定次数。管道字符表示从其左边的内容和右边的内容中选择一个。圆括号表示一个操作符的范围,它们可以与管道(或叫析取)符号一起使用,如«`w(i|e|ai|oo)t`»,匹配 wit, wet, wait 和 woot。你可以省略这个例子里的最后一个表达式中的括号,使用«`ed|ing
......@@ -1501,7 +1501,7 @@ romance 74 193 11 51 45 43
humor 16 30 8 8 9 13
```
回想一下[3.6](./ch03.html#code-stemmer-indexing)中的列表, 我们使用格式字符串`'{:{width}}'`并绑定一个值给 `format()`中的`width`参数。这我们使用变量知道字段的宽度。
回想一下[3.6](./ch03.html#code-stemmer-indexing)中的列表, 我们使用格式字符串`'{:{width}}'`并绑定一个值给`format()`中的`width`参数。这我们使用变量知道字段的宽度。
```py
>>> '{:{width}}' % ("Monty Python", width=15)
......@@ -1567,7 +1567,7 @@ After (5), all (3), is (2), said (4), and (3), done (4), , (1), more
* 在本书中,我们将文本作为一个单词列表。“原始文本”是一个潜在的长字符串,其中包含文字和用于设置格式的空白字符,也是我们通常存储和可视化文本的方式。
* 在 Python 中指定一个字符串使用单引号或双引号:`'Monty Python'``"Monty Python"`
* 字符串中的字符是使用索引来访问的,索引从零计数:`'Monty Python'[0]`给出的值是`M`。字符串的长度使用`len()`得到。
* 子字符串使用切片符号来访问: `'Monty Python'[1:5]` 给出的值是`onty`。如果省略起始索引,子字符串从字符串的开始处开始;如果省略结尾索引,切片会一直到字符串的结尾处结束。
* 子字符串使用切片符号来访问: `'Monty Python'[1:5]`给出的值是`onty`。如果省略起始索引,子字符串从字符串的开始处开始;如果省略结尾索引,切片会一直到字符串的结尾处结束。
* 字符串可以被分割成列表:`'Monty Python'.split()`给出`['Monty', 'Python']`。列表可以连接成字符串:`'/'.join(['Monty', 'Python'])`给出`'Monty/Python'`
* 我们可以使用`text = open('input.txt').read()`从一个文件`input.txt`读取文本。可以使用`text = request.urlopen(url).read().decode('utf8')`从一个`url`读取文本。我们可以使用`for line in open(f)`遍历一个文本文件的每一行。
* 我们可以通过打开一个用于写入的文件`output_file = open('output.txt', 'w')`来向文件写入文本,然后添加内容到文件中`print("Monty Python", file=output_file)`
......@@ -1676,7 +1676,7 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点
21. ◑ 写一个函数`unknown()`,以一个 URL 为参数,返回一个那个网页出现的未知词列表。为了做到这一点,请提取所有由小写字母组成的子字符串(使用`re.findall()`),并去除所有在 Words 语料库(`nltk.corpus.words`)中出现的项目。尝试手动分类这些词,并讨论你的发现。
22. ◑ 使用上面建议的正则表达式处理网址 `http://news.bbc.co.uk/`,检查处理结果。你会看到那里仍然有相当数量的非文本数据,特别是 JavaScript 命令。你可能还会发现句子分割没有被妥善保留。定义更深入的正则表达式,改善此网页文本的提取。
22. ◑ 使用上面建议的正则表达式处理网址`http://news.bbc.co.uk/`,检查处理结果。你会看到那里仍然有相当数量的非文本数据,特别是 JavaScript 命令。你可能还会发现句子分割没有被妥善保留。定义更深入的正则表达式,改善此网页文本的提取。
23. ◑ 你能写一个正则表达式以这样的方式来分词吗,将词 don't 分为 do 和 n't?解释为什么这个正则表达式无法正常工作:«`n't|\w+`»。
......@@ -1693,11 +1693,11 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点
28. ◑ 考虑下面的摘自 MedLine 语料库的句子中的数字表达式:The corresponding free cortisol fractions in these sera were 4.53 +/- 0.15% and 8.16 +/- 0.23%, respectively.我们应该说数字表达式 4.53 +/- 0.15%是三个词吗?或者我们应该说它是一个单独的复合词?或者我们应该说它实际上是*九*个词,因为它读作“four point five three,plus or minus fifteen percent”?或者我们应该说这不是一个“真正的”词,因为它不会出现在任何词典中?讨论这些不同的可能性。你能想出产生这些答案中至少两个以上可能性的应用领域吗?
29. ◑ 可读性测量用于为一个文本的阅读难度打分,给语言学习者挑选适当难度的文本。在一个给定的文本中,让我们定义μ<sub>w</sub>为每个词的平均字母数,μ<sub>s</sub>为每个句子的平均词数。文本自动可读性指数(ARI)被定义为: `4.71` μ<sub>w</sub> `+ 0.5` μ<sub>s</sub> `- 21.43`。计算布朗语料库各部分的 ARI 得分,包括 `f`(lore)和`j`(learned)部分。利用`nltk.corpus.brown.words()`产生一个词汇序列,`nltk.corpus.brown.sents()`产生一个句子的序列的事实。
29. ◑ 可读性测量用于为一个文本的阅读难度打分,给语言学习者挑选适当难度的文本。在一个给定的文本中,让我们定义μ<sub>w</sub>为每个词的平均字母数,μ<sub>s</sub>为每个句子的平均词数。文本自动可读性指数(ARI)被定义为: `4.71` μ<sub>w</sub> `+ 0.5` μ<sub>s</sub> `- 21.43`。计算布朗语料库各部分的 ARI 得分,包括`f`(lore)和`j`(learned)部分。利用`nltk.corpus.brown.words()`产生一个词汇序列,`nltk.corpus.brown.sents()`产生一个句子的序列的事实。
30. ◑ 使用 Porter 词干提取器规范化一些已标注的文本,对每个词调用提取词干器。用 Lancaster 词干提取器做同样的事情,看看你是否能观察到一些差别。
31. ◑ 定义变量`saying`包含列表`['After', 'all', 'is', 'said', 'and', 'done', ',', 'more', 'is', 'said', 'than', 'done', '.']`。使用`for`循环处理这个列表,并将结果存储在一个新的链表`lengths` 中。提示:使用`lengths = []`,从分配一个空列表给`lengths`开始。然后每次循环中用`append()`添加另一个长度值到列表中。现在使用列表推导做同样的事情。
31. ◑ 定义变量`saying`包含列表`['After', 'all', 'is', 'said', 'and', 'done', ',', 'more', 'is', 'said', 'than', 'done', '.']`。使用`for`循环处理这个列表,并将结果存储在一个新的链表`lengths`中。提示:使用`lengths = []`,从分配一个空列表给`lengths`开始。然后每次循环中用`append()`添加另一个长度值到列表中。现在使用列表推导做同样的事情。
32. ◑ 定义一个变量`silly`包含字符串:`'newly formed bland ideas are inexpressible in an infuriating way'`。(这碰巧是合法的解释,讲英语西班牙语双语者可以适用于乔姆斯基著名的无意义短语,colorless green ideas sleep furiously,来自维基百科)。编写代码执行以下任务:
......
......@@ -463,7 +463,7 @@ True
[set(), set(), set(), set(), set(), {'Alice'}, set()]]
```
请看循环变量`i``j`在产生对象过程中没有用到,它们只是需要一个语法正确的`for` 语句。这种用法的另一个例子,请看表达式`['very' for i in range(3)]`产生一个包含三个`'very'`实例的列表,没有整数。
请看循环变量`i``j`在产生对象过程中没有用到,它们只是需要一个语法正确的`for`语句。这种用法的另一个例子,请看表达式`['very' for i in range(3)]`产生一个包含三个`'very'`实例的列表,没有整数。
请注意,由于我们前面所讨论的有关对象复制的原因,使用乘法做这项工作是不正确的。
......@@ -831,7 +831,7 @@ Python 提供一些具有函数式编程语言如 Haskell 标准特征的高阶
21.75081116158339
```
在上面的例子中,我们指定了一个用户定义的函数`is_content_word()` 和一个内置函数`len()`。我们还可以提供一个 lambda 表达式。这里是两个等效的例子,计数每个词中的元音的数量。
在上面的例子中,我们指定了一个用户定义的函数`is_content_word()`和一个内置函数`len()`。我们还可以提供一个 lambda 表达式。这里是两个等效的例子,计数每个词中的元音的数量。
```py
>>> list(map(lambda w: len(filter(lambda c: c.lower() in "aeiou", w)), sent))
......@@ -1027,7 +1027,7 @@ Python 提供了一个调试器,它允许你监视程序的执行,指定程
它会给出一个提示`(Pdb)`,你可以在那里输入指令给调试器。输入`help`来查看命令的完整列表。输入`step`(或只输入`s`)将执行当前行然后停止。如果当前行调用一个函数,它将进入这个函数并停止在第一行。输入`next`(或只输入`n`)是类似的,但它会在当前函数中的下一行停止执行。`break`(或`b`)命令可用于创建或列出断点。输入`continue`(或`c`)会继续执行直到遇到下一个断点。输入任何变量的名称可以检查它的值。
我们可以使用 Python 调试器来查找`find_words()` 函数的问题。请记住问题是在第二次调用函数时产生的。我们一开始将不使用调试器而调用该函数[first-run_](./ch04.html#id9),使用可能的最小输入。第二次我们使用调试器调用它[second-run_](./ch04.html#id11)。.. doctest-ignore:
我们可以使用 Python 调试器来查找`find_words()`函数的问题。请记住问题是在第二次调用函数时产生的。我们一开始将不使用调试器而调用该函数[first-run_](./ch04.html#id9),使用可能的最小输入。第二次我们使用调试器调用它[second-run_](./ch04.html#id11)。.. doctest-ignore:
```py
>>> import pdb
......
......@@ -439,7 +439,7 @@ KeyError: 'green'
这就提出了一个重要的问题。与列表和字符串不同,我们可以用`len()`算出哪些整数是合法索引,我们如何算出一个字典的合法键?如果字典不是太大,我们可以简单地通过查看变量`pos`检查它的内容。正如在前面([](./ch05.html#pos-inspect)行)所看到,这为我们提供了键-值对。请注意它们的顺序与最初放入它们的顺序不同;这是因为字典不是序列而是映射(参见[3.2](./ch05.html#fig-maps02)),键没有固定地排序。
换种方式,要找到键,我们可以将字典转换成一个列表[](./ch05.html#dict-to-list)——要么在期望列表的上下文中使用字典,如作为`sorted()`的参数[](./ch05.html#dict-sorted),要么在`for` 循环中[](./ch05.html#dict-for-loop)
换种方式,要找到键,我们可以将字典转换成一个列表[](./ch05.html#dict-to-list)——要么在期望列表的上下文中使用字典,如作为`sorted()`的参数[](./ch05.html#dict-sorted),要么在`for`循环中[](./ch05.html#dict-for-loop)
```py
>>> list(pos)
......@@ -1173,7 +1173,7 @@ Statement User121 18/m pm me if u tryin to chat
3. 布朗语料库中这些有歧义的词的*词符*的百分比是多少?
19.`evaluate()`方法算出一个文本上运行的标注器的精度。例如,如果提供的已标注文本是`[('the', 'DT'), ('dog', 'NN')]`,标注器产生的输出是`[('the', 'NN'), ('dog', 'NN')]`,那么得分为`0.5`。让我们尝试找出评价方法是如何工作的:
1. 一个标注器`t`将一个词汇列表作为输入,产生一个已标注词列表作为输出。然而,`t.evaluate()`只以一个正确标注的文本作为唯一的参数。执行标注之前必须对输入做些什么?
2. 一旦标注器创建了新标注的文本,`evaluate()` 方法可能如何比较它与原来标注的文本,计算准确性得分?
2. 一旦标注器创建了新标注的文本,`evaluate()`方法可能如何比较它与原来标注的文本,计算准确性得分?
3. 现在,检查源代码来看看这个方法是如何实现的。检查`nltk.tag.api.__file__`找到源代码的位置,使用编辑器打开这个文件(一定要使用文件`api.py`,而不是编译过的二进制文件`api.pyc`)。
20. ◑ 编写代码,搜索布朗语料库,根据标记查找特定的词和短语,回答下列问题:
1. 产生一个标注为`MD`的不同的词的按字母顺序排序的列表。
......
......@@ -325,7 +325,7 @@ if endswith(,) == False:
if endswith(.) == False: return 'NN'
```
在这里,我们可以看到分类器一开始检查一个词是否以逗号结尾——如果是,它会得到一个特别的标记`","`。接下来,分类器检查词是否以`"the"`尾,这种情况它几乎肯定是一个限定词。这个“后缀”被决策树早早使用是因为词"the"太常见。分类器继续检查词是否以"s"结尾。如果是,那么它极有可能得到动词标记`VBZ`(除非它是这个词"is",它有特殊标记`BEZ`),如果不是,那么它往往是名词(除非它是标点符号“.”)。实际的分类器包含这里显示的 if-then 语句下面进一步的嵌套,参数`depth=4` 只显示决策树的顶端部分。
在这里,我们可以看到分类器一开始检查一个词是否以逗号结尾——如果是,它会得到一个特别的标记`","`。接下来,分类器检查词是否以`"the"`尾,这种情况它几乎肯定是一个限定词。这个“后缀”被决策树早早使用是因为词"the"太常见。分类器继续检查词是否以"s"结尾。如果是,那么它极有可能得到动词标记`VBZ`(除非它是这个词"is",它有特殊标记`BEZ`),如果不是,那么它往往是名词(除非它是标点符号“.”)。实际的分类器包含这里显示的 if-then 语句下面进一步的嵌套,参数`depth=4`只显示决策树的顶端部分。
## 1.5 探索上下文语境
......
......@@ -224,7 +224,7 @@ WFST 1 2 3 4 5 6 7
回到我们的表格表示,假设对于词 an 我们有`Det`在(2, 3)单元,对以词 elephant 有`N`在(3, 4)单元,对于 an elephant 我们应该在(2, 4)放入什么?我们需要找到一个形如 *A*`Det N`的产生式。查询了文法,我们知道我们可以输入(0, 2)单元的`NP`
更一般的,我们可以在(i, j)输入 *A*,如果有一个产生式 *A**B* *C*,并且我们在(i, k)中找到非终结符 *B*,在(k, j)中找到非终结符 *C*[4.4](./ch08.html#code-wfst)中的程序使用此规则完成 WFST。通过调用函数`complete_wfst()`时设置 `trace``True`,我们看到了显示 WFST 正在被创建的跟踪输出:
更一般的,我们可以在(i, j)输入 *A*,如果有一个产生式 *A**B* *C*,并且我们在(i, k)中找到非终结符 *B*,在(k, j)中找到非终结符 *C*[4.4](./ch08.html#code-wfst)中的程序使用此规则完成 WFST。通过调用函数`complete_wfst()`时设置`trace``True`,我们看到了显示 WFST 正在被创建的跟踪输出:
```py
>>> wfst1 = complete_wfst(wfst0, tokens, groucho_grammar, trace=True)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册