Token 与 Span
在 spaCy 的文档中,Token 代表文档中的单个单词、标点符号、空格等,而 Span 是文档中的切片。换句话说,Span 是Tokens 的有序序列。
为什么是Spans?
spaCy 的Matcher 提供Span 级别的信息而不是Token 级别,因为它允许匹配Tokens 的序列。就像Span 可以仅由 1 个Token 组成一样,情况不一定如此。
考虑以下示例。我们单独匹配Token"hello",单独匹配Token"world",以及由Tokens "hello" 和"world" 组成的Span。
>>> import spacy
>>> nlp = spacy.load("en")
>>> from spacy.matcher import Matcher
>>> matcher = Matcher(nlp.vocab)
>>> matcher.add(1, None, [{"LOWER": "hello"}])
>>> matcher.add(2, None, [{"LOWER": "world"}])
>>> matcher.add(3, None, [{"LOWER": "hello"}, {"LOWER": "world"}])
对于"Hello world!",所有这些模式都匹配:
>>> document = nlp("Hello world!")
>>> [(token.idx, token) for token in document]
[(0, Hello), (6, world), (11, !)]
>>> matcher(document)
[(1, 0, 1), (3, 0, 2), (2, 1, 2)]
但是,第 3 个模式与 "Hello, world!" 不匹配,因为 "Hello" 和 "world" 不是连续的 Tokens(因为 "," Token),所以它们不匹配形成Span:
>>> document = nlp("Hello, world!")
>>> [(token.idx, token) for token in document]
[(0, Hello), (5, ,), (7, world), (12, !)]
>>> matcher(document)
[(1, 0, 1), (2, 2, 3)]
从Spans 访问Tokens
尽管如此,您应该能够通过迭代 Span 从 span 中获取 Token 级别的信息,就像在 Doc 中迭代 Tokens 一样。
>>> document = nlp("Hello, world!")
>>> span, type(span)
(Hello, world, <class 'spacy.tokens.span.Span'>)
>>> [(token.idx, token, type(token)) for token in span]
[(0, Hello, <class 'spacy.tokens.token.Token'>), (5, ,, <class 'spacy.tokens.token.Token'>), (7, world, <class 'spacy.tokens.token.Token'>)]