添加spacy中缀:适用于大写字母,但不适用于小写字母,括号而不是斜杠

时间:2020-10-13 00:14:42

标签: spacy

我试图确保spacy将点视为单独的令牌,除非它在两位数字之间。我注意到nlp.Defaults.infixes广泛使用环视运算符,因此我遵循了示例:

infixes = nlp.Defaults.infixes + (r'''[;,:]''',
                                  r'(?<=[a-zA-Z_])[\.^]',  r'[\.^](?=[a-zA-Z_])',
                                  ) 
infix_regex = spacy.util.compile_infix_regex(infixes)
nlp.tokenizer.infix_finditer = infix_regex.finditer

现在大写字母的行为符合预期:

list(nlp.tokenizer('HELLO.WORLD'))
[HELLO, ., WORLD]

但是如果右侧为小写,则失败:

list(nlp.tokenizer('HELLO.world'))
[HELLO.world]

list(nlp.tokenizer('hello.world'))
[hello.world]

list(nlp.tokenizer('hello.WORLD'))
[hello, ., WORLD]

另一个示例,正则表达式查找括号而不是斜杠:

infixes = nlp.Defaults.infixes + (r'(?<=[a-zA-Z_])[\.\(\)/](?=[a-zA-Z_])', ) 
infix_regex = spacy.util.compile_infix_regex(infixes)
nlp.tokenizer.infix_finditer = infix_regex.finditer

tests = [
    'mid(inferior',
    'mid/inferior',
    'left.mid',
    'left.mid/inferior']

pattern = re.compile(r'(?<=[a-zA-Z_])[\.\(\)/](?=[a-zA-Z_])')
for tt in tests:
    print("-"*20)
    print(pattern.split(tt))
    print(list(nlp.tokenizer(tt)))

结果:

--------------------
['mid', 'inferior']
[mid, (, inferior]
--------------------
['mid', 'inferior']
[mid, /, inferior]
--------------------
['left', 'mid']
[left.mid]
--------------------
['left', 'mid', 'inferior']
[left.mid/inferior]

正如人们所看到的那样,由于某种原因,正则表达式不会在点上分割,如果单词不是纯字母,则不会在斜杠上分割,即使上述正则表达式不成问题

1 个答案:

答案 0 :(得分:2)

这里的问题是中缀模式的顺序。它使用找到的第一个匹配项,而另一个infix模式在您的模式之前匹配。您可以先添加自定义模式:

infixes = (r'(?<=[a-zA-Z_])[\.\(\)/](?=[a-zA-Z_])', ) + nlp.Defaults.infixes

这可能会导致其他模式的副作用,尤其是如果您首先添加非常短的模式,因此在进行更改之前和之后都要仔细检查数据的总体标记化准确性,以确保其工作符合预期。这样可能很好,但是您可能需要在中间而不是在开始时添加模式以获得预期的结果。

编辑:

这无效,因为URL模式首先进入。

print(nlp.tokenizer.explain("HELLO.world"))
# [('URL_MATCH', 'HELLO.world')]

如果您不关心URL标记化,则可以设置:

nlp.tokenizer.url_match = None

删除将与令牌中的./进行很多交互的URL匹配。