Python NLTK上下文无关语法生成
我正在研究一个使用Unicode字符的非英语解析器。为此,我决定使用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
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)