SPACY Negation Operator in Pattern Matching

Viewed 150

I am trying to write a pattern in spaCy that matches against "black" but not "black beans."

I tried the code below, but it seems to match the token that is next to "black" so long as it is not "bean." How do I modify to match against only "black"?

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

#pattern = [{"LOWER": "black"}, {"LEMMA": {"NOT_IN": ["bean", "beans"]}}]
pattern = [{"LOWER": "black"}, {"LEMMA": "bean", "OP": "!"}]
matcher.add("blackbeans", [pattern])

doc = nlp("I liked the black beans, but the avocado was black making the whole meal blackish-looking and not good.")

matches = matcher(doc)
for match_id, start, end in matches:
    string_id = nlp.vocab.strings[match_id]  # Get string representation
    span = doc[start:end]  # The matched span
    print(match_id, string_id, start, end, span.text)
1 Answers

There's no way to do this - the Matcher returns every token described by the input pattern. The negation pattern also doesn't match non-tokens, so your pattern will fail if "black" is the last token in a sentence.

There are a couple of ways to work around this:

  1. You can always match "black" and post-process the matches. This is very simple, though some people don't like it because it doesn't use the Matcher.
  2. You can use the alignments feature of the Matcher, which tells you which part of the pattern each token matches. This is mainly useful with more complex patterns than the one you're using now.
Related