【问题标题】:How to use NLTK to generate sentences from an induced grammar?如何使用 NLTK 从诱导语法生成句子?
【发布时间】:2013-02-07 05:07:33
【问题描述】:

我有一个(大)已解析句子列表(使用斯坦福解析器解析),例如,句子“现在你可以被娱乐”具有以下树:

(ROOT
  (S
    (ADVP (RB Now))
    (, ,)
    (NP (PRP you))
    (VP (MD can)
      (VP (VB be)
        (VP (VBN entertained))))
    (. .)))

我正在使用一组句子树来使用 nltk 归纳语法:

import nltk

# ... for each sentence tree t, add its production to allProductions
allProductions += t.productions()

# Induce the grammar
S = nltk.Nonterminal('S')
grammar = nltk.induce_pcfg(S, allProductions)

现在我想使用grammar 生成新的随机句子。我的希望是,由于语法是从一组特定的输入示例中学习的,因此生成的句子在语义上将是相似的。我可以在 nltk 中执行此操作吗?

如果我不能使用 nltk 来执行此操作,是否还有其他工具可以获取(可能重新格式化)grammar 并生成句子?

【问题讨论】:

标签: python nlp nltk


【解决方案1】:

首先,如果你生成随机句子,它们可能在语义上是正确的,但它们可能会失去意义。

(听起来有点像麻省理工学院的学生用他们的SCIgen program 做的,这是自动生成的科学论文。顺便说一句,非常有趣。)

无论如何,我自己从来没有这样做过,但似乎可以使用 nltk.bigrams,您可以在 Generating Random Text with Bigramshave a look there

你也可以generate all subtrees of a current tree,不知道是不是你想要的。

【讨论】:

    【解决方案2】:

    使用 nltk Text 对象,您可以在其上调用“generate()”,这将“打印随机文本,使用三元语言模型生成。”http://nltk.org/_modules/nltk/text.html

    【讨论】:

      【解决方案3】:

      在 NLTK 2.0 中,您可以使用nltk.parse.generate 生成所有可能的sentences for a given grammar

      此代码定义了一个函数,该函数应根据 (P)CFG 中的产生式规则生成单个句子。

      # This example uses choice to choose from possible expansions
      from random import choice
      # This function is based on _generate_all() in nltk.parse.generate
      # It therefore assumes the same import environment otherwise.
      def generate_sample(grammar, items=["S"]):
          frags = []
          if len(items) == 1:
              if isinstance(items[0], Nonterminal):
                  for prod in grammar.productions(lhs=items[0]):
                      frags.append(generate_sample(grammar, prod.rhs()))
              else:
                  frags.append(items[0])
          else:
              # This is where we need to make our changes
              chosen_expansion = choice(items)
              frags.append(generate_sample,chosen_expansion)
          return frags
      

      要利用 PCFG 中的权重,您显然希望使用比 choice() 更好的采样方法,后者隐含假设当前节点的所有扩展都是等概率的。

      【讨论】:

        【解决方案4】:

        我从现有的 nltk.CFG 语法生成随机句子的解决方案:

        def generate_sample(grammar, prod, frags):        
            if prod in grammar._lhs_index: # Derivation
                derivations = grammar._lhs_index[prod]            
                derivation = random.choice(derivations)            
                for d in derivation._rhs:            
                    generate_sample(grammar, d, frags)
            elif prod in grammar._rhs_index:
                # terminal
                frags.append(str(prod))
        

        现在可以使用了:

        frags = []  
        generate_sample(grammar, grammar.start(), frags)
        print( ' '.join(frags) )
        

        【讨论】:

        • generate_sample(d, frags) 应该是generate_sample(grammar, d, frags)
        【解决方案5】:

        受上述启发,这里使用迭代而不是递归。

        import random
        
        def rewrite_at(index, replacements, the_list):
            del the_list[index]
            the_list[index:index] = replacements
        
        def generate_sentence(grammar):
            sentence_list = [grammar.start()]
            all_terminals = False
            while not all_terminals:
                all_terminals = True
                for position, symbol in enumerate(sentence_list):
                    if symbol in grammar._lhs_index:
                        all_terminals = False
                        derivations = grammar._lhs_index[symbol]
                        derivation = random.choice(derivations) # or weighted_choice(derivations) if you have a function for that
                        rewrite_at(position, derivation.rhs(), sentence_list)
            return sentence_list
        

        或者如果你想要派生树,这个。

        from nltk.tree import Tree
        
        def tree_from_production(production):
            return Tree(production.lhs(), production.rhs())
        
        def leaf_positions(the_tree):
            return [the_tree.leaf_treeposition(i) for i in range(len(the_tree.leaves()))]
        
        def generate_tree(grammar):
            initial_derivations = grammar._lhs_index[grammar.start()]
            initial_derivation = random.choice(initial_derivations) # or weighed_choice if you have that function
            running_tree = tree_from_production(initial_derivation)
            all_terminals = False
            while not all_terminals:
                all_terminals = True
                for position in leaf_positions(running_tree):
                    node_label = running_tree[position]
                    if node_label in grammar._lhs_index:
                        all_terminals = False
                        derivations = grammar._lhs_index[node_label]
                        derivation = random.choice(derivations) # or weighed_choice if you have that function
                        running_tree[position] = tree_from_production(derivation)
            return running_tree
        

        这是用于 NLTK PCFG 生产规则的 weighted_choice 函数,可与上述内容一起使用,改编自 Ned Batchelder 的回答 here,用于一般加权选择函数:

        def weighted_choice(productions):
            prods_with_probs = [(prod, prod.prob()) for prod in productions]
            total = sum(prob for prod, prob in prods_with_probs)
            r = random.uniform(0, total)
            upto = 0
            for prod, prob in prods_with_probs:
                if upto + prob >= r:
                    return prod
                upto += prob
            assert False, "Shouldn't get here"
        

        【讨论】:

          猜你喜欢
          • 2010-10-10
          • 2014-01-25
          • 2012-01-18
          • 2015-10-25
          • 2019-08-12
          • 2023-03-15
          • 2022-11-11
          • 2013-10-04
          • 1970-01-01
          相关资源
          最近更新 更多