Python NLTK上下文无关语法生成

Python NLTK上下文无关语法生成,python,parsing,nlp,nltk,context-free-grammar,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

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

也许您正在寻找
CFG.fromstring()
(以前是
parse\u CFG()

从NLTK手册(更新为NLTK 3.0)中:


如果您正在创建一个解析器,那么您必须在实际解析之前添加词性标记步骤,因为无法在上下文之外成功确定单词的词性标记。例如,“closed”可以是形容词或动词;词性标记员会从单词的上下文中找出正确的标记。然后,您可以使用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()

您现在不能不费吹灰之力就在nltk中编写此类规则,但您可以使用一些技巧

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

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

变成:

NN V NN.
语法和终端规则示例:

V -> 'V'

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

您可以使用具有decise-token正则表达式功能的NLTKRegexTagger。这正是你需要的。以“ing”结尾的As标记将被标记为动名词,以“ed”结尾的As标记将被标记为动词过去时。请参见下面的示例

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)

您可以使用组合标记器来在一个序列中集体使用多个标记器。

另一个选项是使用正则表达式解析器。看见大概是这样的:

    >>> 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)))        

你可能喜欢阅读,因为你正在写CFG。谢谢。我看了看,但听不懂。有什么方法可以将python变量提供给CFG吗?如果您想自动学习CFG规则,可以尝试实现以下内容:www.aclweb.org/anthology/O06-1004‎ =)谢谢但它仍然硬编码那些动词和名词,对吗?是否仍要将字符串值传递给CFG?就像V=variable_aI一样,我相信您可以连接字符串,然后将它们传入!事实上,根据我在你的原始问题中所理解的,另一件要尝试的事情(不完全确定是否可能)是只对以-ing或-ed结尾的单词进行部分词性标记,并将它们标记为V,这样你就不必担心CFG中的V规则。不,但是NLTK允许你以非常简单的方式训练自己的标记者。然而,为了做到这一点,您需要一些标记的语言语料库来训练统计模型。你有权使用这样的资源吗?你在用什么语言?我需要基于规则的语法生成方法。例如,以-ed或-ing结尾的单词作为动词(在我的应用程序中,我将使用unicode字符)。NLTK有这样做的必要吗?我想这意味着你的语言中没有任何标记语料库?无论如何,如果你想要一个完全基于规则的标记器,你必须自己创建它(自己编写规则,这样“如果单词以这个开头,以那个结尾,前面的单词是这个,那么这个单词就是一个形容词)。我不认为NLTK有这样的机制。但是,我仍然不清楚你到底想做什么,以及为什么你必须使用明确的基于规则的系统。当然欢迎你向我们提供更完整的需求描述。感谢你的帮助。是的,我没有标记语料库。但我需要一些方法来识别POS使用规则,最少硬编码。
regexp_tagger = nltk.RegexpTagger(patterns)
regexp_tagger.tag(your_sent)
    >>> 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)