将一个Tokenizer与NLTK组合成一个语法和解析器

我正在通过NLTK书的方式,我似乎无法做一些似乎是建立一个体面的语法的自然的第一步。

我的目标是为特定的文本语料库构建语法。

(最初的问题:我是否应该尝试从头开始语法,或者我应该从一个预定义的语法开始?如果我应该从另一个语法开始,这对于英语来说是一个好语法?)

假设我有以下简单的语法:

simple_grammar = nltk.parse_cfg("""
S -> NP VP
PP -> P NP
NP -> Det N | Det N PP
VP -> V NP | VP PP
Det -> 'a' | 'A'
N -> 'car' | 'door'
V -> 'has'
P -> 'in' | 'for'
 """);

这个语法可以解析一个非常简单的句子,比如:

parser = nltk.ChartParser(simple_grammar)
trees = parser.nbest_parse("A car has a door")

现在我想扩展这个语法来处理与其他名词和动词的句子。 如何将这些名词和动词添加到我的语法中,而无需在语法中手动定义它们?

例如,假设我想要解析句子“一辆车有车轮”。 我知道提供的标记器可以神奇地找出哪些词是动词/名词等。我怎样才能使用标记器的输出来告诉语法“轮子”是一个名词?


您可以在文本上运行POS标记器,然后使语法适应POS标记而不是文字。

> text = nltk.word_tokenize("A car has a door")
['A', 'car', 'has', 'a', 'door']

> tagged_text = nltk.pos_tag(text)
[('A', 'DT'), ('car', 'NN'), ('has', 'VBZ'), ('a', 'DT'), ('door', 'NN')]

> pos_tags = [pos for (token,pos) in nltk.pos_tag(text)]
['DT', 'NN', 'VBZ', 'DT', 'NN']

> simple_grammar = nltk.parse_cfg("""
  S -> NP VP
  PP -> P NP
  NP -> Det N | Det N PP
  VP -> V NP | VP PP
  Det -> 'DT'
  N -> 'NN'
  V -> 'VBZ'
  P -> 'PP'
  """)

> parser = nltk.ChartParser(simple_grammar)
> tree = parser.parse(pos_tags)

我知道这是一年后,但我想补充一些想法。

我学习了很多不同的句子,并在我正在进行的一个项目中为它们添加词类。 从那里开始,我就像StompChicken建议的那样,从元组(标签,词组)拉出标签,并使用这些标签作为“终端”(树的底部节点,因为我们创建了一个完全标记的句子)。

最终,这不符合我在名词短语中标记头名词的愿望,因为我不能将头部名词“单词”拉到语法中,因为语法只有标签。

所以我所做的是使用一组(单词,标签)元组来创建一个标签字典,将所有带有该标签的单词作为该标签的值。 然后,我将这个字典打印到screen / grammar.cfg(上下文无关语法)文件中。

我用来打印它的表单完全可以通过加载语法文件(parser = nltk.load_parser('grammar.cfg'))来设置解析器,它生成的其中一行如下所示:VBG - >“fencing”| “bonging”|“金额”|“生活”...超过30多个单词...

所以现在我的语法有实际的词作为终端并且分配与nltk.tag_pos相同的标签。

希望这可以帮助其他任何想要自动化标记大型语料库的人,并且仍然会在语法中将实际词语作为终端。

import nltk
from collections import defaultdict

tag_dict = defaultdict(list)

...
    """ (Looping through sentences) """

        # Tag
        tagged_sent = nltk.pos_tag(tokens)

        # Put tags and words into the dictionary
        for word, tag in tagged_sent:
            if tag not in tag_dict:
                tag_dict[tag].append(word)
            elif word not in tag_dict.get(tag):
                tag_dict[tag].append(word)

# Printing to screen
for tag, words in tag_dict.items():
    print tag, "->",
    first_word = True
    for word in words:
        if first_word:
            print """ + word + """,
            first_word = False
        else:
            print "| "" + word + """,
    print ''

解析是一个棘手的问题,很多事情都可能出错!

你需要(至少)三个组件,一个标记器,一个标记器,最后是解析器。

首先,您需要将正在运行的文本标记为令牌列表。 这可以像围绕空格分割输入字符串一样简单,但是如果您正在解析更一般的文本,则还需要处理数字和标点符号,这不是微不足道的。 例如,句子结束时段通常不被视为它所附带的单词的一部分,但通常会标记缩写词的时间段。

当你有一个输入标记列表时,你可以使用标记器来试图确定每个单词的POS,并用它来消除输入标记序列的歧义。 这有两个主要的优点:首先它加快了解析速度,因为我们不再需要考虑由模棱两可的词许可的替代假设,因为POS-标记器已经这样做了。 其次它改善了未知的文字处理,即。 单词不在你的语法中,通过给这些单词分配一个标签(希望是正确的)。 以这种方式组合解析器和标记器是司空见惯的。

然后,POS标签将组成语法中的预端子。预端子是产品的左侧,只有端子作为其右侧。 即在N - >“房屋”,V - >“跳跃”等。N和V是预先安排。 有语法的语法是相当普遍的,只有两端的非终端,生产和词汇生产,一个非终端到一个终端。 这在大多数情况下都具有语言意义,大多数CFG解析器都要求语法采用这种形式。 然而,人们可以用这种方式代表任何CFG,通过在RHS中的任何终端创建“虚拟制作”,而其中没有终端。

如果您希望在语法上制作更多(或更少)细粒度的标签区分,而不是您的标签输出,那么在POS标签和预端子之间进行某种映射可能是必需的。 然后,您可以使用标记器的结果初始化图表,即。 跨越每个输入令牌的适当类别的被动项目。 可悲的是我不知道NTLK,但我确信有一个简单的方法来做到这一点。 当图表播种时,解析可以像平常一样保持连续,并且任何解析树都可以以常规方式提取(也包括词)。

但是,在大多数实际应用中,您会发现解析器可以返回多个不同的分析结果,因为自然语言高度模糊。 我不知道你想要解析什么样的文本语料,但是如果它和自然语言一样,你可能不得不构建某种解析选择模型,这将需要一个树库,一组分析树一些大小从几百到几千个分析,全部取决于你的语法和你需要多准确的结果。 鉴于这个树库可以自动推断出与之相对应的PCFG。 然后,PCFG可以用作排序分析树的简单模型。

所有这些都是你自己做的很多工作。 你用什么解析结果? 您是否查看过NTLK或其他软件包(如StanfordParser或BerkeleyParser)中的其他资源?

链接地址: http://www.djcxy.com/p/73467.html

上一篇: Combining a Tokenizer into a Grammar and Parser with NLTK

下一篇: Google adsense not display in angular 4 website