AssertionError при попытке добавить новый объект с помощью сопоставителя на spaCy

Я пытаюсь сопоставить всю электронную почту, например, просмотреть текст в куче документов, и добавить его к пользовательской метке NER под названием «ЭЛЕКТРОННАЯ ПОЧТА». Вот код для тестового случая.

nlp = spacy.load('en_core_web_sm')
matcher = Matcher(nlp.vocab)

EMAIL = nlp.vocab.strings['EMAIL']

def add_email_ent(matcher, doc, i, matches):
    match_id, start, end = matches[i]
    doc.ents += ((EMAIL, start, end),)

matcher.add('EmailPII', add_email_ent, [{'LIKE_EMAIL': True}])

text = u"Hi, this is John. My email is [email protected] and an alternate is [email protected]"
doc = nlp(text)

matches = matcher(doc)
for i,[match_id, start, end] in enumerate(matches):
    print (i+1, doc[start:end])

for ent in doc.ents:
    print (ent.text, ent.label_)

Вот что я получаю, когда запускаю этот код.

Traceback (most recent call last):
  File "C:/Python27/emailpii.py", line 26, in <module>
    matches = matcher(doc)
  File "matcher.pyx", line 407, in spacy.matcher.Matcher.__call__
  File "C:/Python27/emailpii.py", line 19, in add_event_ent
    doc.ents += ((EMAIL, start, end),)
  File "doc.pyx", line 415, in spacy.tokens.doc.Doc.ents.__get__
  File "span.pyx", line 61, in spacy.tokens.span.Span.__cinit__
AssertionError: 17587345535198158200

Однако при запуске аналогичного примера

import spacy


print "*****************"
print(spacy.__version__)
print "*****************"


from spacy.matcher import Matcher
#from spacy import displacy

nlp = spacy.load('en_core_web_sm')
matcher = Matcher(nlp.vocab)

EVENT = nlp.vocab.strings['EVENT']

def add_event_ent(matcher, doc, i, matches):
    match_id, start, end = matches[i]
    doc.ents += ((EVENT, start, end),)

matcher.add('GoogleIO', add_event_ent,
            [{'ORTH': 'Google'}, {'ORTH': 'I'}, {'ORTH': '/'}, {'ORTH': 'O'}],
            [{'ORTH': 'Google'}, {'ORTH': 'I'}, {'ORTH': '/'}, {'ORTH': 'O'}, {'IS_DIGIT': True}])

text = u"Google I/O was great this year. See you all again in Google I/O 2018"
doc = nlp(text)

matches = matcher(doc)
for i,[match_id, start, end] in enumerate(matches):
    print (i, doc[start:end])

for ent in doc.ents:
    print (ent.text, ent.label_)

#displacy.serve(doc, style = 'ent')

Я получаю вывод по желанию:


2.0.1


(0, ввод-вывод Google)

(1, ввод-вывод Google)

(2, Google I/O, 2018 г.)

(u'Google I/O', u'EVENT')

(u'в этом году', u'ДАТА')

(u'Google I/O 2018', u'СОБЫТИЕ')

Я что-то упустил здесь?


person hkr    schedule 29.11.2017    source источник


Ответы (1)


Я считаю, что ваш первый код не работает, потому что вы не добавили метку Entity для «EMAIL». Второй код работает, потому что EVENT — это уже существующий тип Entity.

В документации не очень ясно, что на самом деле делает первый аргумент метода matcher.add(), но он добавляет для вас метку Entity. Вот две альтернативы, которые должны работать и устранить путаницу:

Альтернатива 1:

import spacy
from spacy.matcher import Matcher

nlp = spacy.load('en_core_web_sm')
matcher = Matcher(nlp.vocab)

#EMAIL = nlp.vocab.strings['EMAIL'] #Not needed

def add_email_ent(matcher, doc, i, matches):
    match_id, start, end = matches[i]
    doc.ents += ((match_id, start, end),)

matcher.add('EMAIL', add_email_ent, [{'LIKE_EMAIL': True}])

text = u"Hi, this is John. My email is [email protected] and an alternate is [email protected]"
doc = nlp(text)

matches = matcher(doc)
for i,[match_id, start, end] in enumerate(matches):
    print (i+1, doc[start:end])

for ent in doc.ents:
    print (ent.text, ent.label_)

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

import spacy
from spacy.matcher import Matcher
from spacy.pipeline import EntityRecognizer

nlp = spacy.load('en_core_web_sm')
matcher = Matcher(nlp.vocab)
ner = EntityRecognizer(nlp.vocab)

ner.add_label('EMAIL')

EMAIL = nlp.vocab.strings['EMAIL']

def add_email_ent(matcher, doc, i, matches):
    match_id, start, end = matches[i]
    doc.ents += ((EMAIL, start, end),)

matcher.add('EmailPII', add_email_ent, [{'LIKE_EMAIL': True}])

text = u"Hi, this is John. My email is [email protected] and an alternate is [email protected]"
doc = nlp(text)

matches = matcher(doc)
for i,[match_id, start, end] in enumerate(matches):
    print (i+1, doc[start:end])

for ent in doc.ents:
    print (ent.text, ent.label_)
person BriWill    schedule 13.12.2017
comment
Спасибо! Это помогло мне понять первый аргумент, переданный в функцию matcher.add. Я решил свою проблему, используя «add_label», а также «утверждая» диапазон. Ждал, чтобы найти лучший способ его реализации. Это помогает. - person hkr; 13.12.2017