Распознавание именованных сущностей с регулярным выражением: NLTK
Я играл с инструментарием NLTK. Я часто сталкивался с этой проблемой и искал решение в Интернете, но нигде не получил удовлетворительного ответа. Поэтому я размещаю свой запрос здесь.
Много раз NER не помечает последовательные NNP как один NE. Я думаю, что редактирование NER для использования RegexpTagger также может улучшить NER.
Пример:
Входные данные:
Барак Обама замечательный человек.
Выход:
Tree ('S', [Tree ('PERSON', [('Barack', 'NNP')]), Tree ('ORGANIZATION', [('Obama', 'NNP')]), ('is', 'VBZ'), ('a', 'DT'), ('great', 'JJ'), ('person', 'NN'), ('.', '.')])
в то время как
вход:
Бывший вице-президент Дик Чейни сказал консервативной радиоведущей Лоре Ингрэхэм, что он "удостоился чести" сравниваться с Дартом Вейдером, находясь на своем посту.
Выход:
Tree ('S', [('Former', 'JJ'), ('Vice', 'NNP'), ('President', 'NNP'), Tree ('NE', [('Dick', ' NNP '), (' Чейни ',' NNP ')]), ("сказали", "VBD"), ("консервативный", "JJ"), ("радио", "NN"), ("хост"), "NN"), Tree ("NE", [("Laura", "NNP"), ("Ingraham", "NNP")]), ("that", "IN"), ("он", 'PRP'), ('
', '
'), (' was ',' VBD '), (' honored ',' VBN '), ("' '", "' '"), (' to ',' TO '), (' be ', 'VB'), ('сравниваемые', 'VBN'), ('to', 'TO'), Tree('NE', [('Darth', 'NNP'), ('Vader', 'NNP')]), ('while', 'IN'), ('in', 'IN'), ('office', 'NN'), ('.', '.')])
Здесь вице /NNP, президент /NNP, (Дик /NNP, Чейни /NNP), правильно извлечен.
Так что я думаю, что если сначала используется nltk.ne_chunk, а затем, если два последовательных дерева являются NNP, есть большие шансы, что оба ссылаются на одну сущность.
Любое предложение будет по достоинству оценено. Я ищу недостатки в моем подходе.
Благодарю.
3 ответа
from nltk import ne_chunk, pos_tag, word_tokenize
from nltk.tree import Tree
def get_continuous_chunks(text):
chunked = ne_chunk(pos_tag(word_tokenize(text)))
prev = None
continuous_chunk = []
current_chunk = []
for i in chunked:
if type(i) == Tree:
current_chunk.append(" ".join([token for token, pos in i.leaves()]))
elif current_chunk:
named_entity = " ".join(current_chunk)
if named_entity not in continuous_chunk:
continuous_chunk.append(named_entity)
current_chunk = []
else:
continue
if continuous_chunk:
named_entity = " ".join(current_chunk)
if named_entity not in continuous_chunk:
continuous_chunk.append(named_entity)
return continuous_chunk
txt = "Barack Obama is a great person."
print get_continuous_chunks(txt)
[из]:
['Barack Obama']
Но учтите, что если предполагается, что непрерывный блок не будет одним NE, то вы бы объединили несколько NE в один. Я не могу думать о таком примере с моей головы, но я уверен, что это произойдет. Но если они не непрерывны, скрипт выше работает нормально:
>>> txt = "Barack Obama is the husband of Michelle Obama."
>>> get_continuous_chunks(txt)
['Barack Obama', 'Michelle Obama']
В ответе @alvas есть ошибка. Ошибка забора. Обязательно запустите эту проверку elif и вне цикла, чтобы не пропустить NE, который появляется в конце предложения. Так:
from nltk import ne_chunk, pos_tag, word_tokenize
from nltk.tree import Tree
def get_continuous_chunks(text):
chunked = ne_chunk(pos_tag(word_tokenize(text)))
prev = None
continuous_chunk = []
current_chunk = []
for i in chunked:
if type(i) == Tree:
current_chunk.append(" ".join([token for token, pos in i.leaves()]))
elif current_chunk:
named_entity = " ".join(current_chunk)
if named_entity not in continuous_chunk:
continuous_chunk.append(named_entity)
current_chunk = []
else:
continue
if current_chunk:
named_entity = " ".join(current_chunk)
if named_entity not in continuous_chunk:
continuous_chunk.append(named_entity)
current_chunk = []
return continuous_chunk
txt = "Barack Obama is a great person and so is Michelle Obama."
print get_continuous_chunks(txt)
@alvas отличный ответ. Это было действительно полезно. Я попытался описать ваше решение более функционально. Все еще должен улучшить это все же.
def conditions(tree_node):
return tree_node.height() == 2
def coninuous_entities(self, input_text, file_handle):
from nltk import ne_chunk, pos_tag, word_tokenize
from nltk.tree import Tree
# Note: Currently, the chunker categorizes only 2 'NNP' together.
docs = input_text.split('\n')
for input_text in docs:
chunked_data = ne_chunk(pos_tag(word_tokenize(input_text)))
child_data = [subtree for subtree in chunked_data.subtrees(filter = self.filter_conditions)]
named_entities = []
for child in child_data:
if type(child) == Tree:
named_entities.append(" ".join([token for token, pos in child.leaves()]))
# Dump all entities to file for now, we will see how to go about that
if file_handle is not None:
file_handle.write('\n'.join(named_entities) + '\n')
return named_entities
Используя функцию условий, можно добавить много условий для фильтрации.