From 9e9d373f7974167d7b52ed3ef7c94c3c50045ce0 Mon Sep 17 00:00:00 2001 From: wizardforcel <562826179@qq.com> Date: Tue, 29 Dec 2020 18:02:16 +0800 Subject: [PATCH] 2020-12-29 18:02:16 --- 1.md | 4 ++-- 10.md | 12 ++++++------ 11.md | 18 +++++++++--------- 3.md | 6 +++--- 4.md | 2 +- 5.md | 2 +- 7.md | 6 +++--- 8.md | 18 +++++++++--------- 9.md | 18 +++++++++--------- 9 files changed, 43 insertions(+), 43 deletions(-) diff --git a/1.md b/1.md index dfc575f..99ae5d9 100644 --- a/1.md +++ b/1.md @@ -648,7 +648,7 @@ what output do you expect here? >>> ``` -注意我们是如何使用两个条件:`len(w) > 7`保证词长都超过七个字母,`fdist5[w] > 7`保证这些词出现超过 7 次。最后,我们已成功地自动识别出与文本内容相关的高频词。这很小的一步却是一个重要的里程碑:一小块代码,处理数以万计的词,产生一些有信息量的输出。 +注意我们是如何使用两个条件:`len(w) > 7`保证词长都超过七个字母,`fdist5[w] > 7`保证这些词出现超过 7 次。最后,我们已成功地自动识别出与文本内容相关的高频词。这很小的一步却是一个重要的里程碑:一小块代码,处理数以万计的词,产生一些有信息量的输出。 ## 3.3 词语搭配和双连词 @@ -838,7 +838,7 @@ word length is less than 5 >>> from __future__ import print_function ``` -如果我们改变测试条件为`len(word) >= 5`来检查`word`的长度是否大于等于`5`,那么测试将不再为真。此时,`if`语句后面的代码段将不会被执行,没有消息显示给用户: +如果我们改变测试条件为`len(word) >= 5`来检查`word`的长度是否大于等于`5`,那么测试将不再为真。此时,`if`语句后面的代码段将不会被执行,没有消息显示给用户: ```py >>> if len(word) >= 5: diff --git a/10.md b/10.md index f05f1bf..83b0faa 100644 --- a/10.md +++ b/10.md @@ -104,7 +104,7 @@ equivalence <-> True ``` -这里有另一种方式可以看到结论如何得出。`SnF -> -FnS`在语义上等价于`-SnF | -FnS`,其中`|`是对应于`or`的二元运算符。在一般情况下,`φ|ψ`在条件`s`中为真,要么`φ`在`s`中为真,要么`ψ`在`s`中为真。现在,假设`SnF`和`-SnF | -FnS`都在`s`中为真。如果`SnF`为真,那么`-SnF`不可能也为真;经典逻辑的一个基本假设是:一个句子在一种情况下不能同时为真和为假。因此,`-FnS`必须为真。 +这里有另一种方式可以看到结论如何得出。`SnF -> -FnS`在语义上等价于`-SnF | -FnS`,其中`|`是对应于`or`的二元运算符。在一般情况下,`φ|ψ`在条件`s`中为真,要么`φ`在`s`中为真,要么`ψ`在`s`中为真。现在,假设`SnF`和`-SnF | -FnS`都在`s`中为真。如果`SnF`为真,那么`-SnF`不可能也为真;经典逻辑的一个基本假设是:一个句子在一种情况下不能同时为真和为假。因此,`-FnS`必须为真。 回想一下,我们解释相对于一个模型的一种逻辑语言的句子,它们是这个世界的一个非常简化的版本。一个命题逻辑的模型需要为每个可能的公式分配值`True`或`False`。我们一步步的来做这个:首先,为每个命题符号分配一个值,然后确定布尔运算符的含义(即 2.1)和运用它们到这些公式的组件的值,来计算复杂的公式的值。`估值`是从逻辑的基本符号映射到它们的值。下面是一个例子: @@ -375,7 +375,7 @@ True 注意 -**轮到你来**:先用笔和纸,然后用`m.evaluate()`,尝试弄清楚`all x.(girl(x) & walk(x))`和`exists x.(boy(x) -> walk(x))`的真值。确保你能理解为什么它们得到这些值。 +**轮到你来**:先用笔和纸,然后用`m.evaluate()`,尝试弄清楚`all x.(girl(x) & walk(x))`和`exists x.(boy(x) -> walk(x))`的真值。确保你能理解为什么它们得到这些值。 ## 3.7 量词范围歧义 @@ -486,7 +486,7 @@ True 'woman': {('c',), ('b',)}} ``` -经再三考虑,我们可以看到我们的假设中没有说 Eve 是论域中唯一的女性,所以反例模型其实是可以接受的。如果想排除这种可能性,我们将不得不添加进一步的假设,如`exists y. all x. (woman(x) -> (x = y))`以确保模型中只有一个女性。 +经再三考虑,我们可以看到我们的假设中没有说 Eve 是论域中唯一的女性,所以反例模型其实是可以接受的。如果想排除这种可能性,我们将不得不添加进一步的假设,如`exists y. all x. (woman(x) -> (x = y))`以确保模型中只有一个女性。 ## 4 英语句子的语义 @@ -940,7 +940,7 @@ d1: ['s0-r1', 's1-r0'] : ([z12,z15],[boy(z12), (([x],[dog(x)]) -> >>> e2 = read_expr('chase') >>> e3 = nltk.sem.ApplicationExpression(e1, e2) >>> print(e3.simplify()) - \x.all y.(dog(y) -> chase(x,pat)) + \x.all y.(dog(y) -> chase(x,pat)) ``` ```py @@ -974,10 +974,10 @@ d1: ['s0-r1', 's1-r0'] : ([z12,z15],[boy(z12), (([x],[dog(x)]) -> ``` ```py - >>> e2 = read_expr('\\P. all x. (dog(x) -> P(x))') + >>> e2 = read_expr('\\P. all x. (dog(x) -> P(x))') >>> e3 = nltk.sem.ApplicationExpression(e1, e2) >>> print(e3.simplify()) - all x.(dog(x) -> bark(x)) + all x.(dog(x) -> bark(x)) ``` 8. ◑ 开发一种方法,翻译英语句子为带有二元广义量词的公式。在此方法中,给定广义量词`Q`,量化公式的形式为`Q(A, B)`,其中`A`和`B`是``类型的表达式。那么,例如`all(A, B)`为真当且仅当`A`表示的是`B`所表示的一个子集。 diff --git a/11.md b/11.md index ca9412c..3eea94c 100644 --- a/11.md +++ b/11.md @@ -266,7 +266,7 @@ sleep: wake * 浅层语义:命名实体和共指标注,语义角色标签。 * 对话与段落:对话行为标记,修辞结构 -不幸的是,现有的语料库之间在如何表示标注上并没有多少一致性。然而,两个大类的标注表示应加以区别。内联标注通过插入带有标注信息的特殊符号或控制序列修改原始文档。例如,为文档标注词性时,字符串`"fly"`可能被替换为字符串`"fly/NN"`来表示词`fly`在文中是名词。相比之下,对峙标注不修改原始文档,而是创建一个新的文档,通过使用指针引用原始文档来增加标注信息。例如,这个新的文档可能包含字符串`"<token id=8 pos='NN'/>"`,表示 8 号词符是一个名词。(我们希望可以确保的分词本身不会变化,因为它会导致默默损坏这种引用。) +不幸的是,现有的语料库之间在如何表示标注上并没有多少一致性。然而,两个大类的标注表示应加以区别。内联标注通过插入带有标注信息的特殊符号或控制序列修改原始文档。例如,为文档标注词性时,字符串`"fly"`可能被替换为字符串`"fly/NN"`来表示词`fly`在文中是名词。相比之下,对峙标注不修改原始文档,而是创建一个新的文档,通过使用指针引用原始文档来增加标注信息。例如,这个新的文档可能包含字符串`"<token id=8 pos='NN'/>"`,表示 8 号词符是一个名词。(我们希望可以确保的分词本身不会变化,因为它会导致默默损坏这种引用。) ## 3.6 标准和工具 @@ -364,7 +364,7 @@ sleep: wake 我们可以用 XML 来表示许多种语言信息。然而,灵活性是要付出代价的。每次我们增加复杂性,如允许一个元素是可选的或重复的,我们对所有访问这些数据的程序都要做出更多的工作。我们也使它更难以检查数据的有效性,或使用一种 XML 查询语言来查询数据。 -因此,使用 XML 来表示语言结构并不能神奇地解决数据建模问题。我们仍然需要解决如何结构化数据,然后用一个模式定义结构,并编写程序读取和写入格式,以及把它转换为其他格式。同样,我们仍然需要遵循一些有关数据规范化的标准原则。这是明智的,可以避免相同信息的重复复制,所以当只有一个副本变化时,不会导致数据不一致。例如,交叉引用表示为``将重复存储一些其他词条的核心词,如果在其他位置的字符串的副本被修改,链接就会被打断。信息类型之间存在的依赖关系需要建模,使我们不能创建没有根的元素。例如,如果 sense 的定义不能作为词条独立存在,那么`sense`就要嵌套在`entry`元素中。多对多关系需要从层次结构中抽象出来。例如,如果一个单词可以有很多对应的`senses`,一个`sense`可以有几个对应的单词,而单词和`senses`都必须作为`(word, sense)`对的列表分别枚举。这种复杂的结构甚至可以分割成三个独立的 XML 文件。 +因此,使用 XML 来表示语言结构并不能神奇地解决数据建模问题。我们仍然需要解决如何结构化数据,然后用一个模式定义结构,并编写程序读取和写入格式,以及把它转换为其他格式。同样,我们仍然需要遵循一些有关数据规范化的标准原则。这是明智的,可以避免相同信息的重复复制,所以当只有一个副本变化时,不会导致数据不一致。例如,交叉引用表示为`headword</xref>`将重复存储一些其他词条的核心词,如果在其他位置的字符串的副本被修改,链接就会被打断。信息类型之间存在的依赖关系需要建模,使我们不能创建没有根的元素。例如,如果 sense 的定义不能作为词条独立存在,那么`sense`就要嵌套在`entry`元素中。多对多关系需要从层次结构中抽象出来。例如,如果一个单词可以有很多对应的`senses`,一个`sense`可以有几个对应的单词,而单词和`senses`都必须作为`(word, sense)`对的列表分别枚举。这种复杂的结构甚至可以分割成三个独立的 XML 文件。 正如我们看到的,虽然 XML 提供了一个格式方便和用途广泛的工具,但它不是能解决一切问题的灵丹妙药。 @@ -783,12 +783,12 @@ Rotokas 数据由 Stuart Robinson 提供,勉方言数据由 Greg Aumann 提供 15. ◑ 写一个递归函数将任意树转换为对应的 XML,其中非终结符不能表示成 XML 元素,叶子表示文本内容,如: ```py - <S> - <NP type="SBJ"> - <NP> - <NNP>Pierre</NNP> - <NNP>Vinken</NNP> - </NP> - <COMMA>,</COMMA> + <S> + <NP type="SBJ"> + <NP> + <NNP>Pierre</NNP> + <NNP>Vinken</NNP> + </NP> + <COMMA>,</COMMA> ``` \ No newline at end of file diff --git a/3.md b/3.md index afa70fe..dee30e6 100644 --- a/3.md +++ b/3.md @@ -691,7 +691,7 @@ NLTK 分词器允许 Unicode 字符串作为输入,并输出相应地 Unicode ### 在 Python 中使用本地编码 -如果你习惯了使用特定的本地编码字符,你可能希望能够在一个 Python 文件中使用你的字符串输入及编辑的标准方法。为了做到这一点,你需要在你的文件的第一行或第二行中包含字符串:`'# -*- coding: <coding> -*-'`。请注意``必须是像`'latin-1'`, `'big5'`或`'utf-8'`这样的字符串 (见 3.4)。 +如果你习惯了使用特定的本地编码字符,你可能希望能够在一个 Python 文件中使用你的字符串输入及编辑的标准方法。为了做到这一点,你需要在你的文件的第一行或第二行中包含字符串:`'# -*- coding: <coding> -*-'`。请注意``必须是像`'latin-1'`, `'big5'`或`'utf-8'`这样的字符串 (见 3.4)。 ![Images/polish-utf8.png](Images/5eeb4cf55b6d18d4bcb098fc72ddc6d7.jpg) @@ -963,7 +963,7 @@ v 93 27 105 48 49 ### 搜索已分词文本 -你可以使用一种特殊的正则表达式搜索一个文本中多个词(这里的文本是一个词符列表)。例如,`"<a> <man>"`找出文本中所有`a man`的实例。尖括号用于标记词符的边界,尖括号之间的所有空白都被忽略(这只对 NLTK 中的`findall()`方法处理文本有效)。在下面的例子中,我们使用`<.*>`❶,它将匹配所有单个词符,将它括在括号里,于是只匹配词(例如`monied`)而不匹配短语(例如,`a monied man`)会生成。第二个例子找出以词`bro`结尾的三个词组成的短语❷。最后一个例子找出以字母`l`开始的三个或更多词组成的序列❸。 +你可以使用一种特殊的正则表达式搜索一个文本中多个词(这里的文本是一个词符列表)。例如,`"<a> <man>"`找出文本中所有`a man`的实例。尖括号用于标记词符的边界,尖括号之间的所有空白都被忽略(这只对 NLTK 中的`findall()`方法处理文本有效)。在下面的例子中,我们使用`<.*>`❶,它将匹配所有单个词符,将它括在括号里,于是只匹配词(例如`monied`)而不匹配短语(例如,`a monied man`)会生成。第二个例子找出以词`bro`结尾的三个词组成的短语❷。最后一个例子找出以字母`l`开始的三个或更多词组成的序列❸。 ```py >>> from nltk.corpus import gutenberg, nps_chat @@ -1441,7 +1441,7 @@ Lee wants a pancake right now '41 ' ``` -字符串默认是左对齐,但可以通过`'>'`对齐选项右对齐。 +字符串默认是左对齐,但可以通过`'>'`对齐选项右对齐。 diff --git a/4.md b/4.md index e987522..5edaf95 100644 --- a/4.md +++ b/4.md @@ -129,7 +129,7 @@ cat ['dog'] ``` -也就是说,我们*不必*在条件中写`if len(element) > 0:`。 +也就是说,我们*不必*在条件中写`if len(element) > 0:`。 使用`if...elif`而不是在一行中使用两个`if`语句有什么区别?嗯,考虑以下情况: diff --git a/5.md b/5.md index 5d28c5b..b34c9c3 100644 --- a/5.md +++ b/5.md @@ -324,7 +324,7 @@ NNS-TL-HL [('Nations', 1)] 请注意`often`后面最高频率的词性是动词。名词从来没有在这个位置出现(在这个特别的语料中)。 -接下来,让我们看一些较大范围的上下文,找出涉及特定标记和词序列的词(在这种情况下,`"<Verb> to <Verb>"`)。在`code-three-word-phrase`中,我们考虑句子中的每个三词窗口❶,检查它们是否符合我们的标准❷。如果标记匹配,我们输出对应的词❸。 +接下来,让我们看一些较大范围的上下文,找出涉及特定标记和词序列的词(在这种情况下,`"<Verb> to <Verb>"`)。在`code-three-word-phrase`中,我们考虑句子中的每个三词窗口❶,检查它们是否符合我们的标准❷。如果标记匹配,我们输出对应的词❸。 ```py from nltk.corpus import brown diff --git a/7.md b/7.md index 28afe52..d72fcbf 100644 --- a/7.md +++ b/7.md @@ -81,7 +81,7 @@ ## 2.2 标记模式 -组成一个词块语法的规则使用标记模式来描述已标注的词的序列。一个标记模式是一个词性标记序列,用尖括号分隔,如``。标记模式类似于正则表达式模式`(3.4)`。现在,思考下面的来自《华尔街日报》的名词短语: +组成一个词块语法的规则使用标记模式来描述已标注的词的序列。一个标记模式是一个词性标记序列,用尖括号分隔,如`
?<JJ>*<NN>`。标记模式类似于正则表达式模式`(3.4)`。现在,思考下面的来自《华尔街日报》的名词短语: ```py another/DT sharp/JJ dive/NN @@ -122,7 +122,7 @@ sentence = [("Rapunzel", "NNP"), ("let", "VBD"), ("down", "RP"), ❶ (S (NP money/NN market/NN) fund/NN) ``` -一旦我们创建了`money market`词块,我们就已经消除了允许`fund`被包含在一个词块中的上下文。这个问题可以避免,使用一种更加宽容的块规则,如`NP: {<NN>+}`。 +一旦我们创建了`money market`词块,我们就已经消除了允许`fund`被包含在一个词块中的上下文。这个问题可以避免,使用一种更加宽容的块规则,如`NP: {<NN>+}`。 注意 @@ -153,7 +153,7 @@ sentence = [("Rapunzel", "NNP"), ("let", "VBD"), ("down", "RP"), ❶ 注意 -**轮到你来**:将上面的例子封装在函数`find_chunks()`内,以一个如`"CHUNK: {<V.*> <TO> <V.*>}"`的词块字符串作为参数。使用它在语料库中搜索其他几种模式,例如连续四个或多个名词,例如`"NOUNS: {<N.*>{4,}}"` +**轮到你来**:将上面的例子封装在函数`find_chunks()`内,以一个如`"CHUNK: {<V.*> <TO> <V.*>}"`的词块字符串作为参数。使用它在语料库中搜索其他几种模式,例如连续四个或多个名词,例如`"NOUNS: {<N.*>{4,}}"` ## 2.5 词缝加塞 diff --git a/8.md b/8.md index 417378d..67c1d6c 100644 --- a/8.md +++ b/8.md @@ -84,11 +84,11 @@ grammar1 = nltk.CFG.fromstring(""" 确保你的文件名后缀为`.cfg`,并且字符串`'file:mygrammar.cfg'`中间没有空格符。如果命令`print(tree)`没有产生任何输出,这可能是因为你的句子`sent`并不符合你的语法。在这种情况下,可以将分析器的跟踪设置打开:`rd_parser = nltk.RecursiveDescentParser(grammar1, trace=2)`。你还可以查看当前使用的语法中的产生式,使用命令`for p in grammar1.productions(): print(p)`。 -当你编写 CFG 在 NLTK 中分析时,你不能将语法类型与词汇项目一起写在同一个产生式的右侧。因此,产生式`PP -> 'of' NP`是不允许的。另外,你不得在产生式右侧仿制多个词的词汇项。因此,不能写成`NP -> 'New York'`,而要写成类似`NP -> 'New_York'`这样的。 +当你编写 CFG 在 NLTK 中分析时,你不能将语法类型与词汇项目一起写在同一个产生式的右侧。因此,产生式`PP -> 'of' NP`是不允许的。另外,你不得在产生式右侧仿制多个词的词汇项。因此,不能写成`NP -> 'New York'`,而要写成类似`NP -> 'New_York'`这样的。 ## 3.3 句法结构中的递归 -一个语法被认为是递归的,如果语法类型出现在产生式左侧也出现在右侧,如 3.3 所示。产生式`Nom -> Adj Nom`(其中`Nom`是名词性的类别)包含`Nom`类型的直接递归,而`S`上的间接递归来自于两个产生式的组合`S -> NP VP`和`VP -> V S`。 +一个语法被认为是递归的,如果语法类型出现在产生式左侧也出现在右侧,如 3.3 所示。产生式`Nom -> Adj Nom`(其中`Nom`是名词性的类别)包含`Nom`类型的直接递归,而`S`上的间接递归来自于两个产生式的组合`S -> NP VP`和`VP -> V S`。 ```py grammar2 = nltk.CFG.fromstring(""" @@ -120,7 +120,7 @@ grammar2 = nltk.CFG.fromstring(""" `RecursiveDescentParser()`接受一个可选的参数`trace`。如果`trace`大于零,则分析器将报告它解析一个文本的步骤。 -递归下降分析有三个主要的缺点。首先,左递归产生式,如`NP -> NP PP`会进入死循环。第二,分析器浪费了很多时间处理不符合输入句子的词和结构。第三,回溯过程中可能会丢弃分析过的成分,它们将需要在之后再次重建。例如,从`VP -> V NP`上回溯将放弃为`NP`创建的子树。如果分析器之后处理`VP -> V NP PP`,那么`NP`子树必须重新创建。 +递归下降分析有三个主要的缺点。首先,左递归产生式,如`NP -> NP PP`会进入死循环。第二,分析器浪费了很多时间处理不符合输入句子的词和结构。第三,回溯过程中可能会丢弃分析过的成分,它们将需要在之后再次重建。例如,从`VP -> V NP`上回溯将放弃为`NP`创建的子树。如果分析器之后处理`VP -> V NP PP`,那么`NP`子树必须重新创建。 递归下降分析是一种自上而下分析。自上而下分析器在检查输入之前先使用文法*预测*输入将是什么!然而,由于输入对分析器一直是可用的,从一开始就考虑输入的句子会是更明智的做法。这种方法被称为自下而上分析,在下一节中我们将看到一个例子。 @@ -152,7 +152,7 @@ NLTK 中提供`ShiftReduceParser()`,移进-归约分析器的一个简单的 移进-规约分析器可以改进执行策略来解决这些冲突。例如,它可以通过只有在不能规约时才移进,解决移进-规约冲突;它可以通过优先执行规约操作,解决规约-规约冲突;它可以从堆栈移除更多的项目。(一个通用的移进-规约分析器,是一个“超前 LR 分析器”,普遍使用在编程语言编译器中。) -移进-规约分析器相比递归下降分析器的好处是,它们只建立与输入中的词对应的结构。此外,每个结构它们只建立一次,例如`NP(Det(the), N(man))`只建立和压入栈一次,不管以后`VP -> V NP PP`规约或者`NP -> NP PP`规约会不会用到。 +移进-规约分析器相比递归下降分析器的好处是,它们只建立与输入中的词对应的结构。此外,每个结构它们只建立一次,例如`NP(Det(the), N(man))`只建立和压入栈一次,不管以后`VP -> V NP PP`规约或者`NP -> NP PP`规约会不会用到。 ## 4.3 左角落分析器 @@ -347,7 +347,7 @@ TV -> 'chased' | 'saw' (. .)) ``` -我们可以利用这些数据来帮助开发一个语法。例如,6.1 中的程序使用一个简单的过滤器找出带句子补语的动词。假设我们已经有一个形如`VP -> Vs S`的产生式,这个信息使我们能够识别那些包括在`Vs`的扩张中的特别的动词。 +我们可以利用这些数据来帮助开发一个语法。例如,6.1 中的程序使用一个简单的过滤器找出带句子补语的动词。假设我们已经有一个形如`VP -> Vs S`的产生式,这个信息使我们能够识别那些包括在`Vs`的扩张中的特别的动词。 ```py def filter(tree): @@ -449,7 +449,7 @@ grammar = nltk.PCFG.fromstring(""" """) ``` -有时可以很方便的将多个产生式组合成一行,如`VP -> TV NP [0.4] | IV [0.3] | DatV NP NP [0.3]`。为了确保由文法生成的树能形成概率分布,PCFG 语法强加了约束,产生式所有给定的左侧的概率之和必须为 1。6.4 中的语法符合这个约束:对`S`只有一个产生式,它的概率是 1.0;对于`VP`,`0.4+0.3+0.3=1.0`;对于`NP`,`0.8+0.2=1.0`。`parse()`返回的分析树包含概率: +有时可以很方便的将多个产生式组合成一行,如`VP -> TV NP [0.4] | IV [0.3] | DatV NP NP [0.3]`。为了确保由文法生成的树能形成概率分布,PCFG 语法强加了约束,产生式所有给定的左侧的概率之和必须为 1。6.4 中的语法符合这个约束:对`S`只有一个产生式,它的概率是 1.0;对于`VP`,`0.4+0.3+0.3=1.0`;对于`NP`,`0.8+0.2=1.0`。`parse()`返回的分析树包含概率: ```py >>> viterbi_parser = nltk.ViterbiParser(grammar) @@ -469,7 +469,7 @@ grammar = nltk.PCFG.fromstring(""" * 依存语法使用产生式指定给定的中心词的依赖是什么。 * 一个句子有一个以上的句法分析就产生句法歧义(如介词短语附着歧义)。 * 分析器是一个过程,为符合语法规则的句子寻找一个或多个相应的树。 -* 一个简单的自上而下分析器是递归下降分析器,在语法产生式的帮助下递归扩展开始符号(通常是`S`),尝试匹配输入的句子。这个分析器并不能处理左递归产生式(如`NP -> NP PP`)。它盲目扩充类别而不检查它们是否与输入字符串兼容的方式效率低下,而且会重复扩充同样的非终结符然后丢弃结果。 +* 一个简单的自上而下分析器是递归下降分析器,在语法产生式的帮助下递归扩展开始符号(通常是`S`),尝试匹配输入的句子。这个分析器并不能处理左递归产生式(如`NP -> NP PP`)。它盲目扩充类别而不检查它们是否与输入字符串兼容的方式效率低下,而且会重复扩充同样的非终结符然后丢弃结果。 * 一个简单的自下而上的分析器是移位-规约分析器,它把输入移到一个堆栈中,并尝试匹配堆栈顶部的项目和语法产生式右边的部分。这个分析器不能保证为输入找到一个有效的解析,即使它确实存在,它建立子结构而不检查它是否与全部语法一致。 ## 8 深入阅读 @@ -515,7 +515,7 @@ grammar = nltk.PCFG.fromstring(""" 13. ☼ 思考词序列:`Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo`。如`http://en.wikipedia.org/wiki/Buffalo_buffalo_Buffalo_buffalo_buffalo_buffalo_Buffalo_buffalo`解释的,这是一个语法正确的句子。思考此维基百科页面上表示的树形图,写一个合适的语法。正常情况下是小写,模拟听到这句话时听者会遇到的问题。你能为这句话找到其他的解析吗?当句子变长时分析树的数量如何增长?(这些句子的更多的例子可以在`http://en.wikipedia.org/wiki/List_of_homophonous_phrases`找到。) -14. ◑ 你可以通过选择`Edit`菜单上的`Edit Grammar`修改递归下降分析器演示程序。改变第二次扩充产生式,即`NP -> Det N PP`为`NP -> NP PP`。使用`Step`按钮,尝试建立一个分析树。发生了什么? +14. ◑ 你可以通过选择`Edit`菜单上的`Edit Grammar`修改递归下降分析器演示程序。改变第二次扩充产生式,即`NP -> Det N PP`为`NP -> NP PP`。使用`Step`按钮,尝试建立一个分析树。发生了什么? 15. ◑ 扩展`grammar2`中的语法,将产生式中的介词扩展为不及物的,及物的和需要`PP`补语的。基于这些产生式,使用前面练习中的方法为句子`Lee ran away home`画一棵树。 @@ -542,7 +542,7 @@ grammar = nltk.PCFG.fromstring(""" 23. ◑ 在本节中,我们说过简单的用术语 N 元组不能描述所有语言学规律。思考下面的句子,尤其是短语`in his turn`的位置。这是基于 N 元组的方法的一个问题吗? - > `What was more, the in his turn somewhat youngish Nikolay Parfenovich also turned out to be the only person in the entire world to acquire a sincere liking to our "discriminated-against" public procurator.` (Dostoevsky: The Brothers Karamazov) + > `What was more, the in his turn somewhat youngish Nikolay Parfenovich also turned out to be the only person in the entire world to acquire a sincere liking to our "discriminated-against" public procurator.` (Dostoevsky: The Brothers Karamazov) 24. ◑ 编写一个递归函数产生嵌套的括号括起的形式的一棵树,显示去掉叶节点之后的子树的非终结符。于是上面的关于 Pierre Vinken 的例子会产生:`[[[NNP NNP]NP , [ADJP [CD NNS]NP JJ]ADJP ,]NP-SBJ MD [VB [DT NN]NP [IN [DT JJ NN]NP]PP-CLR [NNP CD]NP-TMP]VP .]S`。连续的类别应用空格分隔。 25. ◑ 从古登堡工程下载一些电子图书。写一个程序扫描这些文本中任何极长的句子。你能找到的最长的句子是什么?这么长的句子的句法结构是什么? diff --git a/9.md b/9.md index cefb316..2471ef0 100644 --- a/9.md +++ b/9.md @@ -131,7 +131,7 @@ Feature Single Edge Fundamental Rule: (NP[NUM='pl'] (N[NUM='pl'] children)))) ``` -分析过程中的细节对于当前的目标并不重要。然而,有一个实施上的问题与我们前面的讨论语法的大小有关。分析包含特征限制的产生式的一种可行的方法是编译出问题中特征的所有可接受的值,是我们最终得到一个大的完全指定的`(6)`中那样的 CFG。相比之下,前面例子中显示的分析器过程直接与给定语法的未指定的产生式一起运作。特征值从词汇条目“向上流动”,变量值于是通过如`{?n: 'sg', ?t: 'pres'}`这样的绑定(即字典)与那些值关联起来。当分析器装配有关它正在建立的树的节点的信息时,这些变量绑定被用来实例化这些节点中的值;从而通过查找绑定中`?n`和`?t`的值,未指定的`VP[NUM=?n, TENSE=?t] -> TV[NUM=?n, TENSE=?t] NP[]`实例化为`VP[NUM='sg', TENSE='pres'] -> TV[NUM='sg', TENSE='pres'] NP[]`。 +分析过程中的细节对于当前的目标并不重要。然而,有一个实施上的问题与我们前面的讨论语法的大小有关。分析包含特征限制的产生式的一种可行的方法是编译出问题中特征的所有可接受的值,是我们最终得到一个大的完全指定的`(6)`中那样的 CFG。相比之下,前面例子中显示的分析器过程直接与给定语法的未指定的产生式一起运作。特征值从词汇条目“向上流动”,变量值于是通过如`{?n: 'sg', ?t: 'pres'}`这样的绑定(即字典)与那些值关联起来。当分析器装配有关它正在建立的树的节点的信息时,这些变量绑定被用来实例化这些节点中的值;从而通过查找绑定中`?n`和`?t`的值,未指定的`VP[NUM=?n, TENSE=?t] -> TV[NUM=?n, TENSE=?t] NP[]`实例化为`VP[NUM='sg', TENSE='pres'] -> TV[NUM='sg', TENSE='pres'] NP[]`。 最后,我们可以检查生成的分析树(在这种情况下,只有一个)。 @@ -146,7 +146,7 @@ Feature Single Edge Fundamental Rule: ## 1.3 术语 -到目前为止,我们只看到像`sg`和`pl`这样的特征值。这些简单的值通常被称为原子——也就是,它们不能被分解成更小的部分。原子值的一种特殊情况是布尔值,也就是说,值仅仅指定一个属性是真还是假。例如,我们可能要用布尔特征`AUX`区分助动词,如`can`,`may`,`will`和`do`。例如,产生式`V[TENSE=pres, AUX=+] -> 'can'`意味着`can`接受`TENSE`的值为`pres`,并且`AUX`的值为`+`或`true`。有一个广泛采用的约定用缩写表示布尔特征`f`;不用`AUX=+`或`AUX=-`,我们分别用`+AUX`和`-AUX`。这些都是缩写,然而,分析器就像`+`和`-`是其他原子值一样解释它们。`(15)`显示了一些有代表性的产生式: +到目前为止,我们只看到像`sg`和`pl`这样的特征值。这些简单的值通常被称为原子——也就是,它们不能被分解成更小的部分。原子值的一种特殊情况是布尔值,也就是说,值仅仅指定一个属性是真还是假。例如,我们可能要用布尔特征`AUX`区分助动词,如`can`,`may`,`will`和`do`。例如,产生式`V[TENSE=pres, AUX=+] -> 'can'`意味着`can`接受`TENSE`的值为`pres`,并且`AUX`的值为`+`或`true`。有一个广泛采用的约定用缩写表示布尔特征`f`;不用`AUX=+`或`AUX=-`,我们分别用`+AUX`和`-AUX`。这些都是缩写,然而,分析器就像`+`和`-`是其他原子值一样解释它们。`(15)`显示了一些有代表性的产生式: ```py V[TENSE=pres, +AUX] -> 'can' @@ -436,7 +436,7 @@ NP/NP -> Comp -> 'that' ``` -3.1 中的语法包含一个“缺口引进”产生式,即`S[-INV] -> NP S/NP`。为了正确的预填充斜线特征,我们需要为扩展`S`,`VP`和`NP`的产生式中箭头两侧的斜线添加变量值。例如,`VP/?x -> V SBar/?x`是`VP -> V SBar`的斜线版本,也就是说,可以为一个成分的父母`VP`指定斜线值,只要也为孩子`SBar`指定同样的值。最后,`NP/NP ->`允许`NP`上的斜线信息为空字符串。使用 3.1 中的语法,我们可以分析序列`who do you claim that you like`。 +3.1 中的语法包含一个“缺口引进”产生式,即`S[-INV] -> NP S/NP`。为了正确的预填充斜线特征,我们需要为扩展`S`,`VP`和`NP`的产生式中箭头两侧的斜线添加变量值。例如,`VP/?x -> V SBar/?x`是`VP -> V SBar`的斜线版本,也就是说,可以为一个成分的父母`VP`指定斜线值,只要也为孩子`SBar`指定同样的值。最后,`NP/NP ->`允许`NP`上的斜线信息为空字符串。使用 3.1 中的语法,我们可以分析序列`who do you claim that you like`。 ```py >>> tokens = 'who do you claim that you like'.split() @@ -611,7 +611,7 @@ Feature Bottom Up Predict Combine Rule: |. . . [---]| [3:4] N[AGR=[GND='fem', NUM='sg', PER=3]] -> 'Katze' * ``` -跟踪中的最后两个`Scanner`行显示`den`被识别为两个可能的类别:`Det[AGR=[GND='masc', NUM='sg', PER=3], CASE='acc']`和`Det[AGR=[NUM='pl', PER=3], CASE='dat']`。我们从 3.2 中的语法知道`Katze`的类别是`N[AGR=[GND=fem, NUM=sg, PER=3]]`。因而,产生式`NP[CASE=?c, AGR=?a] -> Det[CASE=?c, AGR=?a] N[CASE=?c, AGR=?a]`中没有变量`?a`的绑定,这将满足这些限制,因为`Katze`的`AGR`值将不与`den`的任何一个`AGR`值统一,也就是`[GND='masc', NUM='sg', PER=3]`或`[NUM='pl', PER=3]`。 +跟踪中的最后两个`Scanner`行显示`den`被识别为两个可能的类别:`Det[AGR=[GND='masc', NUM='sg', PER=3], CASE='acc']`和`Det[AGR=[NUM='pl', PER=3], CASE='dat']`。我们从 3.2 中的语法知道`Katze`的类别是`N[AGR=[GND=fem, NUM=sg, PER=3]]`。因而,产生式`NP[CASE=?c, AGR=?a] -> Det[CASE=?c, AGR=?a] N[CASE=?c, AGR=?a]`中没有变量`?a`的绑定,这将满足这些限制,因为`Katze`的`AGR`值将不与`den`的任何一个`AGR`值统一,也就是`[GND='masc', NUM='sg', PER=3]`或`[NUM='pl', PER=3]`。 ## 4 小结 @@ -659,13 +659,13 @@ In the case of complex values, we say that feature structures are themselves typ fs1 = nltk.FeatStruct("[A = ?x, B= [C = ?x]]") fs2 = nltk.FeatStruct("[B = [D = d]]") fs3 = nltk.FeatStruct("[B = [C = d]]") - fs4 = nltk.FeatStruct("[A = (1)[B = b], C->(1)]") - fs5 = nltk.FeatStruct("[A = (1)[D = ?x], C = [E -> (1), F = ?x] ]") + fs4 = nltk.FeatStruct("[A = (1)[B = b], C->(1)]") + fs5 = nltk.FeatStruct("[A = (1)[D = ?x], C = [E -> (1), F = ?x] ]") fs6 = nltk.FeatStruct("[A = [D = d]]") fs7 = nltk.FeatStruct("[A = [D = d], C = [F = [D = d]]]") - fs8 = nltk.FeatStruct("[A = (1)[D = ?x, G = ?x], C = [B = ?x, E -> (1)] ]") + fs8 = nltk.FeatStruct("[A = (1)[D = ?x, G = ?x], C = [B = ?x, E -> (1)] ]") fs9 = nltk.FeatStruct("[A = [B = b], C = [E = [G = e]]]") - fs10 = nltk.FeatStruct("[A = (1)[B = b], C -> (1)]") + fs10 = nltk.FeatStruct("[A = (1)[B = b], C -> (1)]") ``` 在纸上计算下面的统一的结果是什么。(提示:你可能会发现绘制图结构很有用。) @@ -712,7 +712,7 @@ In the case of complex values, we say that feature structures are themselves typ 9. ★ 扩展 NLTK 中特征结构的处理,允许统一值为列表的特征,使用这个来实现一个 HPSG 风格的子类别分析,核心类别的`SUBCAT`是它的补语的类别和它直接父母的`SUBCAT`值的连结。 -10. ★ 扩展 NLTK 的特征结构处理,允许带未指定类别的产生式,例如`S[-INV] --> ?x S/?x`。 +10. ★ 扩展 NLTK 的特征结构处理,允许带未指定类别的产生式,例如`S[-INV] --> ?x S/?x`。 11. ★ 扩展 NLTK 的特征结构处理,允许指定类型的特征结构。 -- GitLab