10

我正在研究一个带有 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?或者使用有限状态机动态生成它们?

4

5 回答 5

8

如果您正在创建解析器,那么您必须在实际解析之前添加一个 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().

于 2013-07-23T23:06:06.630 回答
3

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

从NLTK 书的第 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)))
于 2013-07-19T19:20:26.587 回答
1

您可以使用具有决定令牌正则表达式功能的NLTK RegexTagger 。这正是您需要的。因为以“ing”结尾的标记将被标记为动名词,以“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
 ]

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

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

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

于 2014-07-20T14:27:22.427 回答
0

你现在不能不费吹灰之力地在 nltk 中编写这种规则,但你可以制作一些技巧。

例如,用某种单词信息标签转录你的句子,并相应地写下你的语法规则。

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

Dogs eat bones. 

变成:

NN V NN.

和语法终端规则示例:

V -> 'V'

如果这还不够,您应该寻找更灵活的形式主义实现。

于 2014-05-01T21:08:58.747 回答
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)
于 2021-04-13T00:33:05.247 回答