4.1 用级联词块划分器构建嵌套结构

到目前为止,我们的词块结构一直是相对平的。已标注词符组成的树在如NP这样的词块节点下任意组合。然而,只需创建一个包含递归规则的多级的词块语法,就可以建立任意深度的词块结构。4.1是名词短语、介词短语、动词短语和句子的模式。这是一个四级词块语法器,可以用来创建深度最多为 4 的结构。

  1. grammar = r"""
  2. NP: {<DT|JJ|NN.*>+} # Chunk sequences of DT, JJ, NN
  3. PP: {<IN><NP>} # Chunk prepositions followed by NP
  4. VP: {<VB.*><NP|PP|CLAUSE>+$} # Chunk verbs and their arguments
  5. CLAUSE: {<NP><VP>} # Chunk NP, VP
  6. """
  7. cp = nltk.RegexpParser(grammar)
  8. sentence = [("Mary", "NN"), ("saw", "VBD"), ("the", "DT"), ("cat", "NN"),
  9. ("sit", "VB"), ("on", "IN"), ("the", "DT"), ("mat", "NN")]

不幸的是,这一结果丢掉了 saw 为首的VP。它还有其他缺陷。当我们将此词块划分器应用到一个有更深嵌套的句子时,让我们看看会发生什么。请注意,它无法识别[1]开始的VP词块。

  1. >>> sentence = [("John", "NNP"), ("thinks", "VBZ"), ("Mary", "NN"),
  2. ... ("saw", "VBD"), ("the", "DT"), ("cat", "NN"), ("sit", "VB"),
  3. ... ("on", "IN"), ("the", "DT"), ("mat", "NN")]
  4. >>> print(cp.parse(sentence))
  5. (S
  6. (NP John/NNP)
  7. thinks/VBZ
  8. (NP Mary/NN)
  9. saw/VBD # [_saw-vbd]
  10. (CLAUSE
  11. (NP the/DT cat/NN)
  12. (VP sit/VB (PP on/IN (NP the/DT mat/NN)))))

这些问题的解决方案是让词块划分器在它的模式中循环:尝试完所有模式之后,重复此过程。我们添加一个可选的第二个参数loop指定这套模式应该循环的次数:

  1. >>> cp = nltk.RegexpParser(grammar, loop=2)
  2. >>> print(cp.parse(sentence))
  3. (S
  4. (NP John/NNP)
  5. thinks/VBZ
  6. (CLAUSE
  7. (NP Mary/NN)
  8. (VP
  9. saw/VBD
  10. (CLAUSE
  11. (NP the/DT cat/NN)
  12. (VP sit/VB (PP on/IN (NP the/DT mat/NN)))))))

注意

这个级联过程使我们能创建深层结构。然而,创建和调试级联过程是困难的,关键点是它能更有效地做全面的分析(见第8.章)。另外,级联过程只能产生固定深度的树(不超过级联级数),完整的句法分析这是不够的。