python-3.x - Spacy 实体规则不适用于基数(社会安全号码)

标签 python-3.x spacy named-entity-recognition

我已使用实体规则为社会保障号添加新标签。 我什至设置了 overwrite_ents=true 但它仍然无法识别

我验证了正则表达式是正确的。不知道我还需要做什么 我之前尝试过“ner”但结果相同

text = "My name is yuyyvb and I leave on 605 W Clinton Street. My social security 690-96-4032"
nlp = spacy.load("en_core_web_sm")
ruler = EntityRuler(nlp, overwrite_ents=True)
ruler.add_patterns([{"label": "SSN", "pattern": [{"TEXT": {"REGEX": r"\d{3}[^\w]\d{2}[^\w]\d{4}"}}]}])
nlp.add_pipe(ruler)
doc  = nlp(text)
for ent in doc.ents:
    print("{} {}".format(ent.text, ent.label_))

最佳答案

实际上,您拥有的 SSN 被 spacy 标记为 5 个 block :

print([token.text for token in nlp("690-96-4032")])
# => ['690', '-', '96', '-', '4032']

因此,要么使用自定义分词器,其中 -数字之间的值不会拆分为单独的标记,或者 - 更简单 - 为连续 5 个标记创建一个模式:

patterns = [{"label": "SSN", "pattern": [{"TEXT": {"REGEX": r"^\d{3}$"}}, {"TEXT": "-"}, {"TEXT": {"REGEX": r"^\d{2}$"}}, {"TEXT": "-"}, {"TEXT": {"REGEX": r"^\d{4}$"}} ]}]

完整的 spacy 演示:

import spacy
from spacy.pipeline import EntityRuler

nlp = spacy.load("en_core_web_sm")
ruler = EntityRuler(nlp, overwrite_ents=True)
patterns = [{"label": "SSN", "pattern": [{"TEXT": {"REGEX": r"^\d{3}$"}}, {"TEXT": "-"}, {"TEXT": {"REGEX": r"^\d{2}$"}}, {"TEXT": "-"}, {"TEXT": {"REGEX": r"^\d{4}$"}} ]}]
ruler.add_patterns(patterns)
nlp.add_pipe(ruler)

text = "My name is yuyyvb and I leave on 605 W Clinton Street. My social security 690-96-4032"
doc = nlp(text)
print([(ent.text, ent.label_) for ent in doc.ents])
# => [('605', 'CARDINAL'), ('690-96-4032', 'SSN')]

所以,{"TEXT": {"REGEX": r"^\d{3}$"}}匹配仅由三位数字组成的标记,{"TEXT": "-"}-字符等

使用 spacy 覆盖连字符数字标记化

如果您对如何通过覆盖默认标记化来实现它感兴趣,请注意 infixes :r"(?<=[0-9])[+\-\*^](?=[0-9-])"正则表达式使 spacy 将连字符分隔的数字拆分为单独的标记。使1-2-31-2就像子字符串被标记为单个标记一样,删除 -来自正则表达式。好吧,你不能这样做,这要棘手得多:你需要用 2 个正则表达式替换它: r"(?<=[0-9])[+*^](?=[0-9-])"r"(?<=[0-9])-(?=-)"因为-还在数字 ( (?<=[0-9]) ) 和连字符之间进行检查(请参阅 (?=[0-9-]) )。

所以,整个事情看起来像

import spacy
from spacy.tokenizer import Tokenizer
from spacy.pipeline import EntityRuler
from spacy.util import compile_infix_regex

def custom_tokenizer(nlp):
    # Take out the existing rule and replace it with a custom one:
    inf = list(nlp.Defaults.infixes)
    inf.remove(r"(?<=[0-9])[+\-\*^](?=[0-9-])")
    inf = tuple(inf)
    infixes = inf + tuple([r"(?<=[0-9])[+*^](?=[0-9-])", r"(?<=[0-9])-(?=-)"]) 
    infix_re = compile_infix_regex(infixes)

    return Tokenizer(nlp.vocab, prefix_search=nlp.tokenizer.prefix_search,
                                suffix_search=nlp.tokenizer.suffix_search,
                                infix_finditer=infix_re.finditer,
                                token_match=nlp.tokenizer.token_match,
                                rules=nlp.Defaults.tokenizer_exceptions)

nlp = spacy.load("en_core_web_sm")
nlp.tokenizer = custom_tokenizer(nlp)
ruler = EntityRuler(nlp, overwrite_ents=True)
ruler.add_patterns([{"label": "SSN", "pattern": [{"TEXT": {"REGEX": r"^\d{3}\W\d{2}\W\d{4}$"}}]}])
nlp.add_pipe(ruler)

text = "My name is yuyyvb and I leave on 605 W Clinton Street. My social security 690-96-4032. Some 9---al"
doc = nlp(text)
print([t.text for t in doc])
# =>  ['My', 'name', 'is', 'yuyyvb', 'and', 'I', 'leave', 'on', '605', 'W', 'Clinton', 'Street', '.', 'My', 'social', 'security', '690-96-4032', '.', 'Some', '9', '-', '--al']
print([(ent.text, ent.label_) for ent in doc.ents])
# => [('605', 'CARDINAL'), ('690-96-4032', 'SSN'), ('9', 'CARDINAL')]

如果您遗漏r"(?<=[0-9])-(?=-)"['9', '-', '--al']将变成'9---al' .

注意您需要使用^\d{3}\W\d{2}\W\d{4}$正则表达式:^$匹配 token 的开头和结尾(否则,部分匹配的 token 也将被识别为 SSN)和 [^\w]等于\W .

关于python-3.x - Spacy 实体规则不适用于基数(社会安全号码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58175591/

相关文章:

python - 如何检查一个类是否已在同一模块中的另一个类中使用?

python - 如何清理 pandas 数据框中的图像格式?

python - 代码的时间复杂度是多少?

Python 命名实体识别 (NER) : Replace named entities with labels

java - Freebase 寻找替代公司名称

python - 跟踪变量 - ComboBox Tkinter

python - spacy 3 更新后,NLP 更新无法与元组一起使用

java - 如何在 Java 中使用 GATE Annie 获取命名实体提取?

python - 用前面提到的人替换人称代词(嘈杂的 coref)