Заменить объект на его метку в SpaCy

Может ли SpaCy каким-либо образом заменить объект, обнаруженный SpaCy NER, его меткой? Например: Я ем яблоко, играя со своим Apple Macbook.

Я обучил модель NER с помощью SpaCy для обнаружения сущности «ФРУКТЫ», и модель успешно определяет первое «яблоко» как «ФРУКТЫ», но не второе «яблоко».

Я хочу выполнить постобработку своих данных, заменив каждый объект его меткой, поэтому я хочу заменить первое «яблоко» на «ФРУКТЫ». Предложение будет выглядеть так: «Я ем ФРУКТЫ, играя на своем Apple Macbook».

Если я просто использую регулярное выражение, оно заменит второе «Яблоко» на «ФРУКТЫ», что неверно. Есть ли какой-нибудь умный способ сделать это?

Спасибо!


person eng2019    schedule 05.11.2019    source источник
comment
Пожалуйста, разместите свой код!   -  person chefhose    schedule 05.11.2019


Ответы (3)


метка объекта является атрибутом токена (см. здесь)

import spacy
from spacy import displacy
nlp = spacy.load('en_core_web_lg')

s = "His friend Nicolas is here."
doc = nlp(s)

print([t.text if not t.ent_type_ else t.ent_type_ for t in doc])
# ['His', 'friend', 'PERSON', 'is', 'here', '.']

print(" ".join([t.text if not t.ent_type_ else t.ent_type_ for t in doc]) )
# His friend PERSON is here .

Изменить:

Для обработки случаев, когда сущности могут охватывать несколько слов, вместо этого можно использовать следующий код:

s = "His friend Nicolas J. Smith is here with Bart Simpon and Fred."
doc = nlp(s)
newString = s
for e in reversed(doc.ents): #reversed to not modify the offsets of other entities when substituting
    start = e.start_char
    end = start + len(e.text)
    newString = newString[:start] + e.label_ + newString[end:]
print(newString)
#His friend PERSON is here with PERSON and PERSON.

Обновление:

Цзиньхуа Ван обратил мое внимание на то, что теперь существует более встроенный и более простой способ сделать это с помощью конвейера merge_entities. См. Ответ Цзиньхуа ниже.

person DBaker    schedule 05.11.2019
comment
Спасибо! В любом случае, как я могу сделать так, чтобы он не дублировался, если текст объекта является фразой? Например: его друг Николас Блант здесь. Мне нужно сделать это Его друг ЧЕЛОВЕК здесь. вместо Его друга ЧЕЛОВЕКА здесь .. Спасибо! - person eng2019; 06.11.2019
comment
Я добавил правку для обработки этого случая, когда объекты могут охватывать несколько слов. Надеюсь, это поможет! - person DBaker; 08.11.2019
comment
Это потрясающее решение! - person Jinhua Wang; 11.06.2021
comment
@DBaker см. Мое решение ниже для обновления. - person Jinhua Wang; 16.07.2021

Немного более короткая версия ответа @DBaker, в котором вместо вычисления используется end_char:

for ent in reversed(doc.ents):
    text = text[:ent.start_char] + ent.label_ + text[ent.end_char:]
person nbeuchat    schedule 28.01.2021

Более элегантная модификация приведенного выше решения @DBaker, когда сущности могут охватывать несколько слов:

import spacy
from spacy import displacy
nlp = spacy.load('en_core_web_lg')
nlp.add_pipe("merge_entities")

s = "His friend Nicolas J. Smith is here with Bart Simpon and Fred."
doc = nlp(s)

print([t.text if not t.ent_type_ else t.ent_type_ for t in doc])
# ['His', 'friend', 'PERSON', 'is', 'here', 'with', 'PERSON', 'and', 'PERSON', '.']

print(" ".join([t.text if not t.ent_type_ else t.ent_type_ for t in doc]) )
# His friend PERSON is here with PERSON and PERSON .

Вы можете проверить документацию на Spacy здесь. Он использует встроенный конвейер для работы и имеет хорошую поддержку многопроцессорности. Я считаю, что это официально поддерживаемый способ замены сущностей их тегами.

person Jinhua Wang    schedule 16.07.2021