有没有办法在Spacy中关闭特定的内置令牌化规则?

时间:2019-05-24 09:17:19

标签: nlp tokenize spacy

Spacy自动将单词紧缩(例如“ dont”和“ do n't”)标记为“ do”和“ nt” /“ n't”。例如,类似“我不理解”的句子将被标记为: [“ I”,“ do”,“ nt”,“理解”]

我知道这通常在许多NLP任务中很有用,但是有一种方法可以抑制此special tokenization rule in Spacy,使结果为 [“ I”,“ dont”,“理解”] 相反?

这是因为我正在尝试评估自定义Spacy NER模型的性能(对于BIO标记方案为f1-分数),并且输入句子中的标记数量和谓词标记数量不匹配。我的评估代码的问题:

  • 输入(3个令牌): [(“ I”,“ O”),(“ dont”,“ O”),(“理解”,“ O”)]

  • 已预测(4个令牌): [(“ I”,“ O”),(“ do”,“ O”),(“ nt”,“ O”),(“理解” ,“ O”)]

当然,如果有人对Spacy中的顺序标记任务有更好的评估方法(也许像seqeval包,但更兼容Spacy的令牌格式),也将不胜感激。

1 个答案:

答案 0 :(得分:0)

特殊情况下的标记化规则在相应语言数据的tokenizer_exceptions.py中定义(对于英语“ nt”收缩,则为see here)。创建new Tokenizer时,可以通过rules参数传递那些特殊情况的规则。

方法1:具有不同特殊情况规则的自定义标记生成器

因此,对于您的用例,您可以做的一件事是重建具有相同前缀,后缀和中缀规则的英语Tokenizer,但只过滤掉一组标记符异常。令牌生成器异常由字符串键入,因此您可以删除"dont"以及其他所需项的条目。但是,代码非常冗长,因为您正在重构整个令牌生成器:

from spacy.lang.en import English
from spacy.lang.punctuation import TOKENIZER_PREFIXES, TOKENIZER_SUFFIXES, TOKENIZER_INFIXES                                                                          
from spacy.lang.en import TOKENIZER_EXCEPTIONS  
from spacy.tokenizer import Tokenizer
from spacy.util import compile_prefix_regex, compile_suffix_regex, compile_infix_regex

prefix_re = compile_prefix_regex(TOKENIZER_PREFIXES).search
suffix_re = compile_suffix_regex(TOKENIZER_SUFFIXES).search
infix_re = compile_infix_regex(TOKENIZER_INFIXES).finditer
filtered_exc = {key: value for key, value in TOKENIZER_EXCEPTIONS.items() if key not in ["dont"]} 

nlp = English()
tokenizer = Tokenizer(
    nlp.vocab, 
    prefix_search=prefix_re, 
    suffix_search=suffix_re, 
    infix_finditer=infix_re, 
    rules=filtered_exc
)
nlp.tokenizer = tokenizer
doc = nlp("I dont understand")

方法2:之后合并(或拆分)令牌

另一种方法是保持令牌化不变,但是在规则上添加一些规则,使某些令牌向后合并并重新匹配所需的令牌化。这显然在运行时会变慢,但是可能更易于实现和推理,因为您可以从“哪些标记当前是分离的,但应该是一个?”的角度进行处理。为此,您可以使用rule-based Matcherretokenizer将匹配的令牌合并在一起。从spaCy v2.1开始,如果相关的话,它还支持拆分。

from spacy.lang.en import English
from spacy.matcher import Matcher

nlp = English()
matcher = Matcher(nlp.vocab)
patterns = [[{"LOWER": "do"}, {"LOWER": "nt"}]]
matcher.add("TO_MERGE", None, *patterns)

doc = nlp("I dont understand")
matches = matcher(doc)
with doc.retokenize() as retokenizer:
    for match_id, start, end in matches:
        span = doc[start:end]
        retokenizer.merge(span)

上述模式将匹配两个令牌(每个令牌一个字典),其小写形式为“ do”和“ nt”(例如“ DONT”,“ dont”,“ DoNt”)。您可以将更多字典列表添加到模式中,以描述其他标记序列。对于每次匹配,您都可以创建一个Span并将其合并为一个令牌。为了使这种逻辑更加美观,您还可以将其包装为custom pipeline component,这样当您在文本上调用nlp时它会自动应用。