使用标记语句在 NLTK 中创建解析树

Creating parse trees in NLTK using tagged sentence

使用 the NLTK book 中定义的方法,我想创建一个已经被 POS 标记的句子的分析树。根据我从上面链接的章节中了解到的,任何你想要识别的单词都需要在语法中。这看起来很荒谬,因为有一个内置的 POS 标记器可以让手写每个单词的词性完全多余。我是否缺少允许这样做的解析方法的某些功能?

这里涉及到两种不同的技术。您 link 阅读的章节是关于手写上下文无关语法的,它通常有几十条规则并且可以处理一小部分英语(或您介绍的任何其他语言)。虽然可以基于大量此类规则(加上其他技术)创建一个大覆盖系统,但 NLTK 中的 CFG 实现仅用于教学或演示目的——换句话说,它是一个玩具。甚至不要考虑将其用于通用解析。

对于解析真实文本,有概率解析器,如 Stanford 解析器(nltk 在 nltk.parse.stanford 中有一个接口)。这样的解析器通常是在大型树库上训练的,它们可以处理未知单词,并且正如您所期望的那样,它们要么将 POS 标记的文本作为输入,要么进行自己的 POS 标记。

综上所述,调整 NLTK 的 CFG 机制来处理未知词并不难,如果你有理由这样做:在 POS 标签上而不是在词上写语法(例如,你会写 NP => "DT" "NN", 这样 POS 标签就是终端);然后从你标记的句子中提取 POS 标签,在它们之上构建一个解析树,然后把单词放回去。(如果你的 CFG 包含混合终端和非终端的规则,这将是不够的,比如 "give" NP "to" NP .)

使用 stanford 解析器,不需要词性标记来解析树,因为它内置在模型中。 StanfordParser 和模型不是开箱即用的,需要下载。

大多数人在尝试使用 NLTK

中的 StanfordParser 时会看到此错误
>>> from nltk.parse import stanford
>>> sp = stanford.StanfordParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/anaconda3/lib/python3.5/site-packages/nltk/parse/stanford.py", line 51, in __init__
    key=lambda model_name: re.match(self._JAR, model_name)
  File "/home/user/anaconda3/lib/python3.5/site-packages/nltk/internals.py", line 714, in find_jar_iter
    raise LookupError('\n\n%s\n%s\n%s' % (div, msg, div))
LookupError: 

===========================================================================
  NLTK was unable to find stanford-parser\.jar! Set the CLASSPATH
  environment variable.

  For more information, on stanford-parser\.jar, see:
    <http://nlp.stanford.edu/software/lex-parser.shtml>
===========================================================================

要解决此问题,请将 Stanford Parser 下载到目录并解压缩内容。让我们在 *nix 系统 /usr/local/lib/stanfordparser 上使用示例目录。文件 stanford-parser.jar 必须与其他文件一起位于此处。

当所有文件都存在时,为解析器和模型的位置设置环境变量。

>>> import os
>>> os.environ['STANFORD_PARSER'] = '/usr/local/lib/stanfordparser'
>>> os.environ['STANFORD_MODELS'] = '/usr/local/lib/stanfordparser'

现在您可以使用解析器为您的句子导出可能的解析,例如:

>>> sp = stanford.StanfordParser()
>>> sp.parse("this is a sentence".split())
<list_iterator object at 0x7f53b93a2dd8>
>>> trees = [tree for tree in sp.parse("this is a sentence".split())]
>>> trees[0] # example parsed sentence
Tree('ROOT', [Tree('S', [Tree('NP', [Tree('DT', ['this'])]), Tree('VP', [Tree('VBZ', ['is']), Tree('NP', [Tree('DT', ['a']), Tree('NN', ['sentence'])])])])])

返回一个 iterator 对象,因为给定的句子可以有多个解析器。