Распознавание именованных сущностей NLTK в списке Python

Я использовал ne_chunk NLTK для извлечения именованных сущностей из текста:

my_sent = "WASHINGTON -- In the wake of a string of abuses by New York police officers in the 1990s, Loretta E. Lynch, the top federal prosecutor in Brooklyn, spoke forcefully about the pain of a broken trust that African-Americans felt and said the responsibility for repairing generations of miscommunication and mistrust fell to law enforcement."


nltk.ne_chunk(my_sent, binary=True)

Но я не могу понять, как сохранить эти сущности в список? Например. -

print Entity_list
('WASHINGTON', 'New York', 'Loretta', 'Brooklyn', 'African')

Спасибо.


person Zlo    schedule 05.08.2015    source источник
comment
Что вместо этого возвращает ne_chunk()? В чем именно вы застряли?   -  person lenz    schedule 05.08.2015
comment
возможный дубликат Распознавания именованных сущностей с регулярным выражением: NLTK   -  person alvas    schedule 05.08.2015
comment
Когда я запускаю ваш код, я получаю IndexError   -  person MERose    schedule 01.02.2018
comment
Это немного устарело, но вам нужно сделать что-то вроде nltk.ne_chunk(nltk.pos_tag(nltk.word_tokenize("Welcome to Barbados, Tobdy!")))   -  person Alex Riina    schedule 28.04.2019


Ответы (7)


nltk.ne_chunk возвращает вложенный объект nltk.tree.Tree, поэтому вам придется пройти через объект Tree, чтобы добраться до сетевых элементов.

Взгляните на Распознавание именованных сущностей с регулярным выражением: NLTK

>>> 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)))
...     continuous_chunk = []
...     current_chunk = []
...     for i in chunked:
...             if type(i) == Tree:
...                     current_chunk.append(" ".join([token for token, pos in i.leaves()]))
...             if current_chunk:
...                     named_entity = " ".join(current_chunk)
...                     if named_entity not in continuous_chunk:
...                             continuous_chunk.append(named_entity)
...                             current_chunk = []
...             else:
...                     continue
...     return continuous_chunk
... 
>>> my_sent = "WASHINGTON -- In the wake of a string of abuses by New York police officers in the 1990s, Loretta E. Lynch, the top federal prosecutor in Brooklyn, spoke forcefully about the pain of a broken trust that African-Americans felt and said the responsibility for repairing generations of miscommunication and mistrust fell to law enforcement."
>>> get_continuous_chunks(my_sent)
['WASHINGTON', 'New York', 'Loretta E. Lynch', 'Brooklyn']


>>> my_sent = "How's the weather in New York and Brooklyn"
>>> get_continuous_chunks(my_sent)
['New York', 'Brooklyn']
person alvas    schedule 05.08.2015

Вы также можете извлечь label каждой сущности имени в тексте, используя этот код:

import nltk
for sent in nltk.sent_tokenize(sentence):
   for chunk in nltk.ne_chunk(nltk.pos_tag(nltk.word_tokenize(sent))):
      if hasattr(chunk, 'label'):
         print(chunk.label(), ' '.join(c[0] for c in chunk))

Вывод:

GPE WASHINGTON
GPE New York
PERSON Loretta E. Lynch
GPE Brooklyn

Вы можете видеть, что Washington, New York и Brooklyn GPE означают геополитические образования

и Loretta E. Lynch - это PERSON

person imanzabet    schedule 16.08.2017
comment
Как я могу сохранить результат в списке или массиве, первый столбец GPE и т. Д. И второй столбец Вашингтон и т. Д. - person PV8; 24.05.2019
comment
вы можете определить список кортежей. например, поверх кода добавьте lst=[] Затем вместо функции печати в последней строке lst.append((chunk.label(), chunk[0][0])) - person imanzabet; 28.05.2019

Поскольку вы получаете tree в качестве возвращаемого значения, я думаю, вы захотите выбрать те поддеревья, помеченные NE

Вот простой пример, чтобы собрать всех в список:

import nltk

my_sent = "WASHINGTON -- In the wake of a string of abuses by New York police officers in the 1990s, Loretta E. Lynch, the top federal prosecutor in Brooklyn, spoke forcefully about the pain of a broken trust that African-Americans felt and said the responsibility for repairing generations of miscommunication and mistrust fell to law enforcement."

parse_tree = nltk.ne_chunk(nltk.tag.pos_tag(my_sent.split()), binary=True)  # POS tagging before chunking!

named_entities = []

for t in parse_tree.subtrees():
    if t.label() == 'NE':
        named_entities.append(t)
        # named_entities.append(list(t))  # if you want to save a list of tagged words instead of a tree

print named_entities

Это дает:

[Tree('NE', [('WASHINGTON', 'NNP')]), Tree('NE', [('New', 'NNP'), ('York', 'NNP')])]

или в виде списка списков:

[[('WASHINGTON', 'NNP')], [('New', 'NNP'), ('York', 'NNP')]]

См. Также: Как перемещаться по nltk.tree.Tree?

person b3000    schedule 05.08.2015

используйте tree2conlltags из nltk.chunk. Также ne_chunk нуждается в тегах pos, которые маркируют токены слов (следовательно, требуется word_tokenize).

from nltk import word_tokenize, pos_tag, ne_chunk
from nltk.chunk import tree2conlltags

sentence = "Mark and John are working at Google."
print(tree2conlltags(ne_chunk(pos_tag(word_tokenize(sentence))
"""[('Mark', 'NNP', 'B-PERSON'), 
    ('and', 'CC', 'O'), ('John', 'NNP', 'B-PERSON'), 
    ('are', 'VBP', 'O'), ('working', 'VBG', 'O'), 
    ('at', 'IN', 'O'), ('Google', 'NNP', 'B-ORGANIZATION'), 
    ('.', '.', 'O')] """

Это даст вам список кортежей: [(token, pos_tag, name_entity_tag)] Если этот список не совсем то, что вам нужно, конечно, легче проанализировать нужный список из этого списка, чем дерево nltk.

Код и сведения из этой ссылки; проверьте это для получения дополнительной информации

Вы также можете продолжить, только извлекая слова, с помощью следующей функции:

def wordextractor(tuple1):

    #bring the tuple back to lists to work with it
    words, tags, pos = zip(*tuple1)
    words = list(words)
    pos = list(pos)
    c = list()
    i=0
    while i<= len(tuple1)-1:
        #get words with have pos B-PERSON or I-PERSON
        if pos[i] == 'B-PERSON':
            c = c+[words[i]]
        elif pos[i] == 'I-PERSON':
            c = c+[words[i]]
        i=i+1

    return c

print(wordextractor(tree2conlltags(nltk.ne_chunk(nltk.pos_tag(nltk.word_tokenize(sentence))))

Edit Добавлена ​​строка вывода ** Edit * Добавлен вывод только для B-Person

person elwhite    schedule 12.02.2018

Tree - это список. Чанки - это поддеревья, а неразделенные слова - это обычные строки. Итак, давайте спустимся по списку, извлечем слова из каждого фрагмента и присоединимся к ним.

>>> chunked = nltk.ne_chunk(my_sent)
>>>
>>>  [ " ".join(w for w, t in elt) for elt in chunked if isinstance(elt, nltk.Tree) ]
['WASHINGTON', 'New York', 'Loretta E. Lynch', 'Brooklyn']
person alexis    schedule 31.05.2017

Вы также можете рассмотреть возможность использования Spacy:

import spacy
nlp = spacy.load('en')

doc = nlp('WASHINGTON -- In the wake of a string of abuses by New York police officers in the 1990s, Loretta E. Lynch, the top federal prosecutor in Brooklyn, spoke forcefully about the pain of a broken trust that African-Americans felt and said the responsibility for repairing generations of miscommunication and mistrust fell to law enforcement.')

print([ent for ent in doc.ents])

>>> [WASHINGTON, New York, the 1990s, Loretta E. Lynch, Brooklyn, African-Americans]
person Nic Scozzaro    schedule 16.03.2018

nltk.ne_chunk возвращает вложенный объект nltk.tree.Tree, поэтому вам придется пройти через объект Tree, чтобы добраться до сетевых элементов. Вы можете использовать понимание списка, чтобы сделать то же самое.

import nltk   
my_sent = "WASHINGTON -- In the wake of a string of abuses by New York police officers in the 1990s, Loretta E. Lynch, the top federal prosecutor in Brooklyn, spoke forcefully about the pain of a broken trust that African-Americans felt and said the responsibility for repairing generations of miscommunication and mistrust fell to law enforcement."

word = nltk.word_tokenize(my_sent)   
pos_tag = nltk.pos_tag(word)   
chunk = nltk.ne_chunk(pos_tag)   
NE = [ " ".join(w for w, t in ele) for ele in chunk if isinstance(ele, nltk.Tree)]   
print (NE)
person Akshay    schedule 24.03.2020