Позволяет начать с малого и правильно захватить NP (существительные фразы):
import nltk
grammar = r"""
NP: {<DT|JJ|NN.*>+}
"""
sentence = 'The house and tree'
chunkParser = nltk.RegexpParser(grammar)
words = nltk.word_tokenize(sentence)
tagged = nltk.pos_tag(words)
print(chunkParser.parse(tagged))
[выход]:
(S (NP The/DT house/NN) and/CC (NP tree/NN))
Теперь попробуем поймать это and/CC
. Просто добавьте фразу более высокого уровня, которая использует правило <NP>
:
grammar = r"""
NP: {<DT|JJ|NN.*>+}
CNP: {<NP><CC><NP>}
"""
sentence = 'The house and tree'
chunkParser = nltk.RegexpParser(grammar)
words = nltk.word_tokenize(sentence)
tagged = nltk.pos_tag(words)
print(chunkParser.parse(tagged))
[выход]:
(S (CNP (NP The/DT house/NN) and/CC (NP tree/NN)))
Теперь, когда мы ловим NP CC NP
фраз, давайте немного придумаем и посмотрим, поймает ли он запятые:
grammar = r"""
NP: {<DT|JJ|NN.*>+}
CNP: {<NP><CC|,><NP>}
"""
sentence = 'The house, the bear and tree'
chunkParser = nltk.RegexpParser(grammar)
words = nltk.word_tokenize(sentence)
tagged = nltk.pos_tag(words)
print(chunkParser.parse(tagged))
Теперь мы видим, что он ограничен ловлей первого ограниченного слева NP CC|, NP
и оставил последний NP один.
Так как мы знаем, что в английском языке конъюнктивные фразы имеют ограниченное в левой части соединение и правую ограниченную NP, то есть CC|, NP
, например, and the tree
, мы видим, что шаблон CC|, NP
является повторяющимся, поэтому мы можем использовать его в качестве промежуточного представления.
grammar = r"""
NP: {<DT|JJ|NN.*>+}
XNP: {<CC|,><NP>}
CNP: {<NP><XNP>+}
"""
sentence = 'The house, the bear and tree'
chunkParser = nltk.RegexpParser(grammar)
words = nltk.word_tokenize(sentence)
tagged = nltk.pos_tag(words)
print(chunkParser.parse(tagged))
[выход]:
(S
(CNP
(NP The/DT house/NN)
(XNP ,/, (NP the/DT bear/NN))
(XNP and/CC (NP tree/NN))))
В конечном счете, грамматика CNP
(Conjunctive NPs) фиксирует соединение цепочечной фразы в английском языке, даже сложные, например,
import nltk
grammar = r"""
NP: {<DT|JJ|NN.*>+}
XNP: {<CC|,><NP>}
CNP: {<NP><XNP>+}
"""
sentence = 'The house, the bear, the green house and a tree went to the park or the river.'
chunkParser = nltk.RegexpParser(grammar)
words = nltk.word_tokenize(sentence)
tagged = nltk.pos_tag(words)
print(chunkParser.parse(tagged))
[выход]:
(S
(CNP
(NP The/DT house/NN)
(XNP ,/, (NP the/DT bear/NN))
(XNP ,/, (NP the/DT green/JJ house/NN))
(XNP and/CC (NP a/DT tree/JJ)))
went/VBD
to/TO
(CNP (NP the/DT park/NN) (XNP or/CC (NP the/DT river/NN)))
./.)
А если вам просто интересно извлечь фразы из существительного, из Как пройти по объекту дерева NLTK? :
noun_phrases = []
def traverse_tree(tree):
if tree.label() == 'CNP':
noun_phrases.append(' '.join([token for token, tag in tree.leaves()]))
for subtree in tree:
if type(subtree) == nltk.tree.Tree:
traverse_tree(subtree)
return noun_phrases
sentence = 'The house, the bear, the green house and a tree went to the park or the river.'
chunkParser = nltk.RegexpParser(grammar)
words = nltk.word_tokenize(sentence)
tagged = nltk.pos_tag(words)
traverse_tree(chunkParser.parse(tagged))
[выход]:
['The house , the bear , the green house and a tree', 'the park or the river']
Также см. Python (NLTK) - более эффективный способ извлечения имен существительных?