Не условие в 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 немного сбивает с толку и труднодоступна, поэтому я много боролся, чтобы добиться чего-то подобного.
Проверьте следующие ссылки:
- NLTK Как разбить
- nltk.chunk.regexp
- Книга НЛТК - Глава 07
- ↑ перейти к 2.3 к 2.5
Следуя ответу @Luda, я нашел простое решение:
- Разделите то, что вы хотите: теги
*<другие теги>. Это создаст чанки, начинающиеся с любого слова с 0 или более тегами . - Свяжите теги
из предыдущего выражения фрагмента. Это приведет к удалению всех фрагментов, начинающихся с одного слова с тегом (звездочку мы удалили).
Пример (принимая вопрос @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.
Итак, чтобы построить ретроспективный обзор, мы могли бы попробовать следующее:
- Разделите то, что вы хотите, включая тег
в начале, а затем другие теги, которые вы хотите. Это создаст чанки, начинающиеся с любого слова с 0 или более тегами . - 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
"""