Spacy matcher терпит неудачу на всех остановках

#python #nlp #spacy

Вопрос:

Я новичок в spacy и играю со следующим сценарием;

 import spacy
from spacy.language import Language
from spacy.matcher import Matcher

nlp  = spacy.load('en_core_web_sm')
text = "Google announced a new Pixel at Google I/O. The Google I/O is a great place to get all the updates from Google I/O."

def add_event_ent(matcher, doc, i, matches):
    match_id, start, end = matches[i]
    entity = doc[start:end]
    print(entity.text, start, end)

pattern = [[
  {"TEXT": "Google"}, 
  {"TEXT": "I"}, 
  {"TEXT": "/"}, 
  {"TEXT": "O"}, 
  {"IS_PUNCT": True, "OP": "?"}
]]
matcher = Matcher(nlp.vocab)
matcher.add("Google", pattern, on_match = add_event_ent)

doc = nlp(text)
matcher(doc)
 

Выход:

 Google I/O 11 15
[(11578853341595296054, 11, 15)]
 

Я ожидал бы, что это обнаружит все 3 случая Google I/O , но это не так, и я не совсем уверен, почему. Я попробовал несколько разных вещей, но ничего не сработало, я думаю, что проблема в полной остановке.

Я написал то, что в основном является одним и тем же фрагментом кода с другим текстом и шаблоном:

 text = "Hello, World! Hello, World! How are you?"
pattern = [[
  {"LOWER": "hello"},
  {"IS_PUNCT": True},
  {"LOWER": "world"}
]]
matcher = Matcher(nlp.vocab)
matcher.add("Google", pattern, on_match = add_event_ent)
doc = nlp(text)
matcher(doc)
for ent in doc.ents:
  print(f"[ENTITY] {ent.text:{15}} {ent.label_}")
print(doc)
 

Выход:

 Hello, World 0 3
Hello, World 4 7
Hello, World! Hello, World! How are you?
 

Что, как вы можете видеть, сработало.

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

Любая помощь будет признательна, и дайте мне знать, если я смогу предоставить дополнительную информацию!

Комментарии:

1. Проблема связана с токенизацией, O. имеет . внутри этот токен.

2. Хм, я понимаю, в этом есть смысл, почему он обнаруживает только один из 3. Но как мне это исправить?

Ответ №1:

Проблема связана с токенизацией, O. токен содержит . символ в конце текста этого токена.

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

 pattern = [[
  {"TEXT": "Google"}, 
  {"TEXT": "I"}, 
  {"TEXT": "/"}, 
  {"TEXT": {"REGEX": r"^O(?:_|[^ws])?$"}}
]]
 

Выход:

 Google I/O. 6 10
Google I/O 11 15
Google I/O. 25 29
 

Здесь {"TEXT": {"REGEX": r"^O(?:_|[^ws])?$"}} будет соответствовать маркеру, который содержит один или два символа, начиная с O и затем содержащий необязательный знак препинания.

  • ^ — запуск токена (строки, в общем случае)
  • O O чар
  • (?:_|[^ws])? — a _ или ( | ) любой символ, отличный от символа слова и пробела ( [^ws] , класс отрицаемых символов, w обозначает буквы, цифры и подчеркивания и s обозначает пробелы), один или ноль раз (из-за ? квантора)
  • $ — конец токена (строки, в общем случае)