NLTK Генерация предложений без двух вхождений одного и того же слова в Python

Я использую этот код NLTK для создания предложений из demo_grammar (см. ниже), и проблема в том, что с такими грамматическими правилами, как NN или NN N, я получаю такие предложения, как «творение, создание, создание». Меня интересует только создание предложений, в которых одно и то же слово не встречается дважды (например, программное обеспечение для создания видео).

Как я мог это сделать?

generate.py из NLTK выглядит так: https://github.com/nltk/nltk/blob/develop/nltk/parse/generate.py

Я попробовал демо-код из generate.py:

from nltk.grammar import CFG
from nltk.parse import generate    

demo_grammar = """
  S -> NP VP
  NP -> Det N
  PP -> P NP
  VP -> 'slept' | 'saw' NP | 'walked' PP
  Det -> 'the' | 'a'
  N -> 'man' | 'park' | 'dog'
  P -> 'in' | 'with'
"""

def demo(N=23):

    print('Generating the first %d sentences for demo grammar:' % (N,))
    print(demo_grammar)
    grammar = CFG.fromstring(demo_grammar)
    for n, sent in enumerate(generate(grammar, n=N), 1):
        print('%3d. %s' % (n, ' '.join(sent)))

person vandernath    schedule 10.03.2016    source источник
comment
Каждое расширение правила не зависит от других; вот что такое контекстно-свободная грамматика. Можно ли переписать грамматику? Вы можете делать то, что хотите, исключая терминалы из своей грамматики и добавляя их в качестве отдельного шага.   -  person alexis    schedule 10.03.2016


Ответы (1)


Вы можете переписать грамматику, как предложил Алексис, это означает несколько списков терминов (существительных, глаголов,...) для определенного места в каждом предложении.

Но вы также можете применить стратегию постфильтрации (не обязательно касаться грамматики):

  • генерировать все возможные предложения с вашей грамматикой, даже предложения со словами, встречающимися дважды или более
  • применить фильтр, удаляющий все предложения, в которых слова встречаются дважды или более

Вот фильтр, который вы можете применить:

from collections import Counter
f=lambda sent:False if Counter(sent.split(" ")).most_common(1)[0][1] > 1 else True

f("creation video software") # return True, good sentence
f("creation creation creation") # return False, bad sentence
f("creation software creation") # return False, bad sentence
person Anthony Sigogne    schedule 11.03.2016
comment
Красиво и просто, но причина, по которой я предложил изменить грамматику, заключается в том, что этот фильтр неизбежно удаляет слишком много: например, вы выбросите кошку, севшую на коврик. (это происходит дважды, ужасы!) И нет никакого способа ограничить это, так как вывод не имеет структуры или даже частей речи. Но эй, если это достаточно хорошо для OP... - person alexis; 13.03.2016