spaCy - Самый эффективный способ сортировки сущностей по меткам

Я использую конвейер spaCy для извлечения всех сущностей из статей. Мне нужно сохранить эти объекты в переменной в зависимости от метки, которой они были помечены. На данный момент у меня есть это решение, но я думаю, что оно не самое подходящее, так как мне нужно перебирать все сущности для каждой метки:

nlp = spacy.load("es_core_news_md")
text = # I upload my text here
doc = nlp(text)

personEntities = list(set([e.text for e in doc.ents if e.label_ == "PER"]))
locationEntities = list(set([e.text for e in doc.ents if e.label_ == "LOC"]))
organizationEntities = list(set([e.text for e in doc.ents if e.label_ == "ORG"]))

Есть ли в spaCy прямой метод для получения всех сущностей для каждой метки, или мне нужно будет сделать for ent in ents: if... elif... elif... для этого?


person Luiscri    schedule 27.11.2019    source источник
comment
Используйте itertools, чтобы groupby сущности.   -  person Wiktor Stribiżew    schedule 27.11.2019
comment
Используйте словарь для группировки по сущностям, где ключ - это тип сущности   -  person Dani Mesejo    schedule 27.11.2019
comment
@ WiktorStribiżew Не могли бы вы подробнее рассказать о том, как вы бы использовали groupby для этого?   -  person AMC    schedule 27.11.2019
comment
Добавьте from itertools import *. Затем используйте entities = {key: list(g) for key, g in groupby(doc.ents, lambda x: x.label_)}. Позже вы сможете использовать его как print(entities['DATE']) и т. Д.   -  person Wiktor Stribiżew    schedule 27.11.2019
comment
@ WiktorStribiżew Это будет работать, только если метки идут подряд   -  person Dani Mesejo    schedule 27.11.2019
comment
@DanielMesejo Нет проблем, мы можем отсортировать их раньше, entities = {key: list(g) for key, g in groupby(sorted(doc.ents, key=lambda x: x.label_), lambda x: x.label_)}   -  person Wiktor Stribiżew    schedule 27.11.2019
comment
@ WiktorStribiżew Согласен   -  person Dani Mesejo    schedule 27.11.2019


Ответы (1)


Предлагаю использовать метод groupby из itertools:

from itertools import *
#...
entities = {key: list(g) for key, g in groupby(sorted(doc.ents, key=lambda x: x.label_), lambda x: x.label_)}

Или, если вам нужно извлечь только уникальные значения:

entities = {key: list(set(map(lambda x: str(x), g))) for key, g in groupby(sorted(doc.ents, key=lambda x: x.label_), lambda x: x.label_)}

Затем вы можете распечатать известные объекты, используя

print(entities['ORG'])

Если вам нужно получить уникальные экземпляры объектов сущности, а не только строки, вы можете использовать

import spacy
from itertools import *

nlp = spacy.load("en_core_web_sm")
s = "Hello, Mr. Wood! We are in New York. Mrs. Winston is not coming, John hasn't sent her any invite. They will meet in California next time. General Motors and Toyota are companies."
doc = nlp(s * 2)

entities = dict()
for key, g in groupby(sorted(doc.ents, key=lambda x: x.label_), lambda x: x.label_):
    seen = set()
    l = []
    for ent in list(g):
      if ent.text not in seen:
        seen.add(ent.text)
        l.append(ent)
    entities[key] = l

Вывод для print(entities['GPE'][0].text) здесь New York.

person Wiktor Stribiżew    schedule 27.11.2019
comment
Как я могу добиться вывода entities['ORG'] в виде списка без повторяющихся элементов? Я пытался сделать то же самое, что делал до list(set(entities['ORG'])), но, похоже, это не сработало - person Luiscri; 27.11.2019
comment
@Luiscri Это должно сработать, не могли бы вы показать результат entities['ORG']? - person Wiktor Stribiżew; 27.11.2019
comment
print(entities['ORG'] возвращает это: [Asociación Española de Fabricantes de Automóviles y Camiones, PSA, Ford, Renault, Unión Europea, UE, IDAE, Ejecutivo, IDAE, Instituto para la Diversificación, IDAE, Administración] - person Luiscri; 27.11.2019
comment
print(set(entities['ORG'])) возвращает это: {Asociación Española de Fabricantes de Automóviles y Camiones, IDAE, IDAE, Instituto para la Diversificación, Ejecutivo, IDAE, UE, Ford, Administración, PSA, Unión Europea, Renault} - person Luiscri; 27.11.2019
comment
Не уверен, но попробуйте также list(set(map(lambda x: str(x), entities['ORG']) )). Однако код был протестирован на небольшом предложении, и он сработал. - person Wiktor Stribiżew; 27.11.2019
comment
Вот и все, они не сохранялись как строки, так что теперь с картой все заработало. Могу ли я решить эту проблему, изменив ваше решение, например {key: list(str(g) for key, g...? - person Luiscri; 27.11.2019
comment
@Luiscri Да, list(g) = ›list(set(map(lambda x: str(x), g))) - person Wiktor Stribiżew; 27.11.2019
comment
Отлично, теперь это выглядит отлично. Спасибо за уделенное время. - person Luiscri; 27.11.2019
comment
Извините за то, что возродил это, но как я могу получить список уникальных объектов, отсортированных по их меткам? Я имею в виду, что сначала идут все сущности ORG (т.е.), затем все PER ... И что элементы списка по-прежнему являются объектами сущностей с их значениями .text и .label_. Я уже давно пытаюсь это понять и не могу - person Luiscri; 29.01.2020
comment
На всякий случай уведомление до вас не дошло @WiktorStribizew - person Luiscri; 29.01.2020
comment
Как определить пару повторяющихся сущностей? - person Wiktor Stribiżew; 29.01.2020
comment
Имея одинаковые атрибуты .text и .label_ @WiktorStribizew - person Luiscri; 29.01.2020
comment
Разве это не тот же результат, который мы получили со вторым решением, которое вы опубликовали? Я не совсем об этом спрашивал. Я имел в виду: я хочу получить только список со всеми сущностями, как тот, который я получаю, создавая документы. Однако мне нужно, чтобы объекты в этом списке были отсортированы по его метке, то есть сначала отображались все сущности с меткой LOC, затем все сущности с меткой PER, а затем все сущности с меткой ORG. Более того, я хочу, чтобы если два объекта имели одинаковый текст и метку, они отображались только один раз. Я думаю, что это можно сделать только одной строкой в ​​качестве ваших первых ответов, но я не могу это понять - person Luiscri; 30.01.2020