spaCy:Matcher 结束令牌偏移量不是我所期望的

spaCy: Matcher end token offset not what I am expecting

使用 spaCy(2.0.11 根据 spacy.info()),我尝试使用 Matcher 识别标记模式,但没有得到预期的结果。匹配对象中的标记偏移量与文本中应该匹配的标记偏移量不对应。

这是一个简化的代码片段来展示我在做什么:

import spacy
from spacy.matcher import Matcher

nlp = spacy.load('en')

text = "This has not gone far. The end."
doc = nlp(text)

pattern1 = [{'POS': 'VERB'}, {'LEMMA': 'not'}, {'POS': 'VERB'}] # match has not gone
pattern2 = [{'POS': 'DET'}, {'POS': 'NOUN'}] # match The end

matcher = Matcher(nlp.vocab)

matcher.add('rule1', None, pattern1)
matcher.add('rule2', None, pattern2)

matches = matcher(doc)

for match in matches:
    print(doc[match[1]], doc[match[2]], match)

我得到的输出是:

has far (15137773209560627690, 1, 4)
The . (16952143625379849586, 6, 8)

我期望的输出是:

has gone (15137773209560627690, 1, 3)
The end (16952143625379849586, 6, 7)

所以匹配的结束标记偏移量是模式匹配的最后一个标记之后标记的偏移量。这是预期的行为吗?

更一般地说,我正在尝试生成 TokensRegex 样式的行为,以便能够将自定义注释添加到给定匹配项中的各个标记(例如,向 "has" 和 [= 添加 negated=TRUE 注释) 32=] 和在同一个匹配中对副词 "not" 的否定=TRUE 注释)。可以将单个注释添加到具有回调函数的匹配中,但这并不是我所追求的。这可能(还)吗?

我认为问题在于您只查看开始和结束 token,而不是匹配的跨度。跨度的 end 索引始终是独占的,因此 doc[2:4] 将是标记 2 标记 4。我刚刚尝试了您的示例并打印了每个匹配跨度的文本,我看到了以下输出:

for match_id, start, end in matches:
    span = doc[start:end]
    print(span.text)

# has not gone
# The end

回答你的第二个问题:你可以使用 custom extension attributes like token._.negated and token._.negation to achieve something very similar. If your negation rule matches, you could create a Span for the match, iterate over the tokens and set the respective attributes. To make this more elegant, you can also wrap that logic in a pipeline component,所以当你在文本上调用 nlp 时它会自动 运行。