NLTK Context Free Grammar Genaration

时间:2013-07-17 09:06:53

标签: python parsing nlp nltk context-free-grammar

我正在使用带有Unicode字符的非英语解析器。为此,我决定使用NLTK。

但它需要一个预定义的无上下文语法,如下所示:

  S -> NP VP
  VP -> V NP | V NP PP
  PP -> P NP
  V -> "saw" | "ate" | "walked"
  NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
  Det -> "a" | "an" | "the" | "my"
  N -> "man" | "dog" | "cat" | "telescope" | "park"
  P -> "in" | "on" | "by" | "with" 

在我的应用程序中,我应该使用基于规则的语法来最小化硬编码。 例如,我可以假设以 -ed -ing 结尾的任何单词作为动词。所以它应该适用于任何给定的上下文。

如何将此类语法规则提供给NLTK?或者使用有限状态机动态生成它们?

5 个答案:

答案 0 :(得分:7)

如果你正在创建一个解析器,那么<​​strong>有在实际解析之前添加一个pos-tagging步骤 - 没有办法成功确定一个单词的POS-tag上下文。例如,'封闭'可以是形容词或动词; POS标签可以从单词的上下文中找到适合您的标签。然后,您可以使用POS标记器的输出来创建CFG。

您可以使用众多现有POS标签之一。在NLTK中,您可以简单地执行以下操作:

import nltk
input_sentence = "Dogs chase cats"
text = nltk.word_tokenize(input_sentence)
list_of_tokens = nltk.pos_tag(text)
print list_of_tokens

输出将是:

[('Dogs', 'NN'), ('chase', 'VB'), ('cats', 'NN')]

您可以使用它来创建语法字符串并将其提供给nltk.parse_cfg()

答案 1 :(得分:2)

也许您正在寻找CFG.fromstring()(以前为parse_cfg())?

来自NLTK书籍的Chapter 7(更新为NLTK 3.0):

> grammar = nltk.CFG.fromstring("""
 S -> NP VP
 VP -> V NP | V NP PP
 V -> "saw" | "ate"
 NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
 Det -> "a" | "an" | "the" | "my"
 N -> "dog" | "cat" | "cookie" | "park"
 PP -> P NP
 P -> "in" | "on" | "by" | "with"
 """)

> sent = "Mary saw Bob".split()
> rd_parser = nltk.RecursiveDescentParser(grammar)
> for p in rd_parser.parse(sent):
      print p
(S (NP Mary) (VP (V saw) (NP Bob)))

答案 2 :(得分:1)

您可以使用具有正则表达能力决定令牌的NLTK RegexTagger 。这正是您需要的。作为令牌结尾的标记&#39;将被标记为动名词和令牌以“&#39; ed”结尾。将用动词过去标记。见下面的例子。

patterns = [
    (r'.*ing$', 'VBG'), # gerunds
    (r'.*ed$', 'VBD'), # simple past
    (r'.*es$', 'VBZ'), # 3rd singular present
    (r'.*ould$', 'MD'), # modals
    (r'.*\'s$', 'NN$'), # possessive nouns
    (r'.*s$', 'NNS') # plural nouns
 ]

请注意,这些按顺序处理,并应用匹配的第一个。现在 我们可以设置一个标记器并用它来标记一个句子。在这一步之后,关于a是正确的 五分之一。

regexp_tagger = nltk.RegexpTagger(patterns)
regexp_tagger.tag(your_sent)

您可以使用组合标记在序列中共同使用多个标记。

答案 3 :(得分:0)

你现在不能在nltk中编写这样的规则而不需要任何努力,但你可以制定一些技巧。

例如,在某些单词信息标签中转录您的句子并相应地写出您的语法规则。

例如(使用POS标签作为标签):

Dogs eat bones. 

变为:

NN V NN.

语法终端规则示例:

V -> 'V'

如果这还不够,你应该考虑更灵活的形式主义实施。

答案 4 :(得分:0)

另一种选择是使用正则表达式解析器。见https://www.nltk.org/book/ch07.html。像这样:

    >>> import nltk, re, pprint
    >>> from nltk import word_tokenize, sent_tokenize
    >>> my_sentence = "This is just an example"
    >>> tokenized_sentence = word_tokenize(my_sentence)
    >>> tagged_sentence = nltk.pos_tag(tokenized_sentence)
    >>> grammar = """
    ...   P:   {<IN>}
    ...   N:   {<NN.*>}
    ...   DET: {<DT>}
    ...   NP:  {<DET><N><PP>?}
    ...        {<NNP>}
    ...   V:   {<VB.*>}
    ...   PP:  {<P><NP>}
    ...   VP:  {<V><NP>}
    ...        {<V><NP><PP>}
    ...   S:   {<NP><VP>}
    ... """
    >>> cp = nltk.RegexpParser(grammar)
    >>> tree = cp.parse(tagged_sentence)
    >>> print(tree)
    (S (DET This/DT) (V is/VBZ) just/RB (NP (DET an/DT) (N example/NN)))        

缺点是,如果您正在寻找特定的硬编码词,这不会直接告诉您。但是,您可以使用类似的方法处理树并找出单词。上面链接中的书对此进行了描述。

 for subtree in tree.subtrees():
        if subtree.label() == 'N': 
            noun = subtree[0][0]
            do_something(noun)