1.1 语言数据和无限可能性

前面的章节中已经为你讲述了如何处理和分析的文本语料库,我们一直强调处理大量的每天都在增加的电子语言数据是 NLP 的挑战。让我们更加细致的思考这些数据,做一个思想上的实验,我们有一个巨大的语料库,包括在过去 50 年中英文表达或写成的一切。我们称这个语料库为“现代英语”合理吗?有许多为什么我们的回答可能是否定的的原因。回想一下,在3中,我们让你搜索网络查找 the of 模式的实例。虽然很容易在网上找到包含这个词序列的例子,例如 New man at the of IMG (见http://www.telegraph.co.uk/sport/2387900/New-man-at-the-of-IMG.html),说英语的人会说大多数这样的例子是错误的,因此它们根本不是英语。

因此,我们可以说,“现代英语”并不等同于我们想象中的语料库中的非常大的词序列的集合。说英语的人可以判断这些序列,并将拒绝其中一些不合语法的。

同样,组成一个新的句子,并让说话者认为它是非常好的英语是很容易的。例如,句子有一个有趣的属性,它们可以嵌入更大的句子中。考虑下面的句子:

  1. >>> groucho_grammar = nltk.CFG.fromstring("""
  2. ... S -> NP VP
  3. ... PP -> P NP
  4. ... NP -> Det N | Det N PP | 'I'
  5. ... VP -> V NP | VP PP
  6. ... Det -> 'an' | 'my'
  7. ... N -> 'elephant' | 'pajamas'
  8. ... V -> 'shot'
  9. ... P -> 'in'
  10. ... """)

这个文法允许以两种方式分析句子,取决于介词短语 in my pajamas 是描述大象还是枪击事件。

  1. >>> sent = ['I', 'shot', 'an', 'elephant', 'in', 'my', 'pajamas']
  2. >>> parser = nltk.ChartParser(groucho_grammar)
  3. >>> for tree in parser.parse(sent):
  4. ... print(tree)
  5. ...
  6. (S
  7. (NP I)
  8. (VP
  9. (VP (V shot) (NP (Det an) (N elephant)))
  10. (PP (P in) (NP (Det my) (N pajamas)))))
  11. (S
  12. (NP I)
  13. (VP
  14. (V shot)
  15. (NP (Det an) (N elephant) (PP (P in) (NP (Det my) (N pajamas))))))

程序产生两个括号括起的结构,我们可以用树来表示它们,如(3b)所示:

  1. grammar1 = nltk.CFG.fromstring("""
  2. S -> NP VP
  3. VP -> V NP | V NP PP
  4. PP -> P NP
  5. V -> "saw" | "ate" | "walked"
  6. NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
  7. Det -> "a" | "an" | "the" | "my"
  8. N -> "man" | "dog" | "cat" | "telescope" | "park"
  9. P -> "in" | "on" | "by" | "with"
  10. """)

3.1中的语法包含涉及各种句法类型的产生式,如在3.1中所列出的。

表 3.1:

句法类型

  1. >>> grammar1 = nltk.data.load('file:mygrammar.cfg')
  2. >>> sent = "Mary saw Bob".split()
  3. >>> rd_parser = nltk.RecursiveDescentParser(grammar1)
  4. >>> for tree in rd_parser.parse(sent):
  5. ... print(tree)

确保你的文件名后缀为.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'这样的。