Не условие в NLTK Regex Parser

Мне нужно создать условие not как часть моей грамматики в анализаторе регулярных выражений NLTK. Я хотел бы разбить те слова, которые имеют структуру 'Coffee & Tea' но это не должно быть, если есть слово типа <IN> до последовательности. Например 'in London and Paris' не должен быть разбит парсером

Мой код выглядит следующим образом:

grammar = r'''NP: {(^<IN>)<NNP>+<CC><NN.*>+}'''

Я пробовал вышеупомянутую грамматику, чтобы решить проблему, но она не работает, может кто-то, пожалуйста, скажите мне, что я делаю неправильно.

Пример:

def parse_sentence(sentence):
    pos_sentence = nltk.pos_tag(nltk.word_tokenize(sentence))
    grammar = r'''NP: {<NNP>+<CC><NN.*>+}'''
    parser = nltk.RegexpParser(grammar)
    result = parser.parse(pos_sentence)
    print result

sentence1 = 'Who is the front man of the band that wrote Coffee & TV?'
parse_sentence(sentence1)

sentence2 = 'Who of those resting in Westminster Abbey wrote a book set in London and Paris?'
parse_sentence(sentence2)

Result for sentence 1 is:
(S
  Who/WP
  is/VBZ
  the/DT
  front/JJ
  man/NN
  of/IN
  the/DT
  band/NN
  that/WDT
  wrote/VBD
  (NP Coffee/NNP &/CC TV/NN)
  ?/.)

Result for sentence2 is:
(S
  Who/WP
  of/IN
  those/DT
  resting/VBG
  in/IN
  Westminster/NNP
  Abbey/NNP
  wrote/VBD
  a/DT
  book/NN
  set/VBN
  in/IN
  (NP London/NNP and/CC Paris/NNP)
  ?/.)

Как видно из предложения 1 и предложения 2, фразы Coffee & Tea а также London and Paris быть разделенным на группы, хотя я не хочу разделять London and Paris, Один из способов сделать это - игнорировать те шаблоны, которым предшествует <IN> POS Tag.

В двух словах мне нужно знать, как добавить условия NOT(отрицание) для POS-тегов в грамматику синтаксического анализатора регулярных выражений. Стандартный синтаксис использования '^' с последующим определением тега не работает

2 ответа

То, что вам нужно, это выражение "негативный взгляд за спиной". К сожалению, это не работает в парсере чанков, поэтому я подозреваю, что то, что вы хотите, не может быть указано как регулярное выражение чанкинга.

Вот обычный негативный взгляд за спиной: соответствует "Париж", но не в том случае, если ему предшествует "и".

>>> re.findall(r"(?<!and) Paris", "Search in London and Paris etc.")
[]

К сожалению, соответствующее правило разбиения за кадром не работает. Механизм регулярных выражений nltk настраивает регулярное выражение, которое вы передаете ему, для интерпретации типов POS, и это сбивает с толку взгляды. (Я угадываю < символ в синтаксисе lookbehind неправильно интерпретируется как разделитель тегов.)

>>> parser = nltk.RegexpParser(r"NP: {(?<!<IN>)<NNP>+<CC><NN.*>+}")
...
ValueError: Illegal chunk pattern: {(?<!<IN>)<NNP>+<CC><NN.*>+}

Документация по разделению тегов NLTK немного сбивает с толку и труднодоступна, поэтому я много боролся, чтобы добиться чего-то подобного.

Проверьте следующие ссылки:

Следуя ответу @Luda, я нашел простое решение:

  1. Разделите то, что вы хотите: теги *<другие теги>. Это создаст чанки, начинающиеся с любого слова с 0 или более тегами .
  2. Свяжите теги из предыдущего выражения фрагмента. Это приведет к удалению всех фрагментов, начинающихся с одного слова с тегом (звездочку мы удалили).

Пример (принимая вопрос @Ram G Athreya):

def parse_sentence(sentence):
pos_sentence = nltk.pos_tag(nltk.word_tokenize(sentence))

grammar = r'''
    NP: {<IN>*<NNP>+<CC><NN.*>+}
        }<IN><NNP>+<CC><NN.*>+{
        '''
parser = nltk.RegexpParser(grammar)
result = parser.parse(pos_sentence)
print (result)

sentence1 = 'Who is the front man of the band that wrote Coffee & TV?'
parse_sentence(sentence1)

sentence2 = 'Who of those resting in Westminster Abbey wrote a book set in London and Paris?'
parse_sentence(sentence2)


 (S
  Who/WP
  is/VBZ
  the/DT
  front/JJ
  man/NN
  of/IN
  the/DT
  band/NN
  that/WDT
  wrote/VBD
  (NP Coffee/NNP &/CC TV/NN)
  ?/.)
(S
  Who/WP
  of/IN
  those/DT
  resting/VBG
  in/IN
  Westminster/NNP
  Abbey/NNP
  wrote/VBD
  a/DT
  book/NN
  set/VBN
  in/IN
  London/NNP
  and/CC
  Paris/NNP
  ?/.)

Теперь он разбивает "кофе и ТВ", но не "Лондон и Париж".


Более того, это полезно для построения утверждений просмотра назад, в RegExp обычно ?<=, Но это создает конфликт с символами < и >, используемыми в регулярном выражении грамматики chunk_tag.

Итак, чтобы построить ретроспективный обзор, мы могли бы попробовать следующее:

  1. Разделите то, что вы хотите, включая тег в начале, а затем другие теги, которые вы хотите. Это создаст чанки, начинающиеся с любого слова с 0 или более тегами .
  2. Chink тег из предыдущего выражения фрагмента. Это удалит все слова с тегами из блоков.

Пример 2 - Разделите все слова, которым предшествует слово с тегом :

def parse_sentence(sentence):
pos_sentence = nltk.pos_tag(nltk.word_tokenize(sentence))

grammar = r'''
    CHUNK: {<IN>+<.*>}
        }<IN>{
        '''
parser = nltk.RegexpParser(grammar)
result = parser.parse(pos_sentence)
print (result)

sentence1 = 'Who is the front man of the band that wrote Coffee & TV?'
parse_sentence(sentence1)

sentence2 = 'Who of those resting in Westminster Abbey wrote a book set in London and Paris?'
parse_sentence(sentence2)

(S
  Who/WP
  is/VBZ
  the/DT
  front/JJ
  man/NN
  of/IN
  (CHUNK the/DT)
  band/NN
  that/WDT
  wrote/VBD
  Coffee/NNP
  &/CC
  TV/NN
  ?/.)
(S
  Who/WP
  of/IN
  (CHUNK those/DT)
  resting/VBG
  in/IN
  (CHUNK Westminster/NNP)
  Abbey/NNP
  wrote/VBD
  a/DT
  book/NN
  set/VBN
  in/IN
  (CHUNK London/NNP)
  and/CC
  Paris/NNP
  ?/.)

Как мы видим, он выделил "the" из предложения1; "те", "Вестминстер" и "Лондон" из предложения 2

Ср.2.5 "Чикинг"

"Мы можем определить чинк как последовательность токенов, которые не включены в чанк"

http://www.nltk.org/book/ch07.html

Смотрите обратные фигурные скобки для исключения

grammar = 
        r"""
          NP:
            {<.*>+}          # Chunk everything
            }<VBD|IN>+{      # Chink sequences of VBD and IN

         """
Другие вопросы по тегам