Spacy - 使用 PhraseMatcher 创建嵌套分类法

Spacy - create a nested taxonomy using PhraseMatcher

我正在使用 Spacy PhraseMatcher 函数从短文本列表中检测某些特定的分类法。 这是一个示例列表:

SK-washer SKM16-FSt-Geomet 321A
SK-washer SKM20-FSt-Geomet 321A
SK-washer SKM24-FSt-Geomet 321A
Hexagon head bolt M12x80 ISO 4014-8.8-Geomet 321A+VL
Hexagon head bolt M12x90 ISO 4014-8.8-Geomet 321A+VL
Hexagon head bolt M20x90 ISO 4014-8.8-Geomet 3

我正在使用此代码:

import spacy
from spacy.matcher import PhraseMatcher
from spacy.tokens import Span
nlp = spacy.blank('en')

mat_type = [nlp(text) for text in ('screw', 'bolt', 'washer')]
head_type = [nlp(text) for text in ('hexa', 'hexagon')]
geomet_type = [nlp(text) for text in ('321a+vl', '500a', '321a')]
iso_norm = [nlp(text) for text in ('4014','4014-A2-70','4017-8.8', '7040', '7040-8', '7042-10')]

#iso_4014_A2 = [nlp(text) for text in ('ISO', '4014','A2','70')]

matcher = PhraseMatcher(nlp.vocab)
matcher.add('MAT_TYPE', None, *mat_type)
matcher.add('HEAD_TYPE', None, *head_type)
matcher.add('GEOMET_TYPE', None, *geomet_type)
matcher.add('ISO_NORM', None, *iso_norm)
#matcher.add('ISO_4014_A2', None, *iso_4014_A2)
#https://spacy.io/usage/rule-based-matching
with open('./sample_list.txt', 'r') as infile:
    data = infile.readlines()
    for i in data:
        print(i)
        doc = nlp(i.lower())
        matches = matcher(doc)
        for match_id, start, end in matches:
            rule_id = nlp.vocab.strings[match_id]  # get the unicode ID, i.e. 'COLOR'
            span = doc[start : end]  # get the matched slice of the doc
            print(rule_id, span.text)

所以我能够产生这个输出:

Hexagon head bolt M12x90 ISO 4014-8.8-Geomet 321A+VL

HEAD_TYPE hexagon
MAT_TYPE bolt
ISO_NORM 4014
GEOMET_TYPE 321a+vl

我需要创建一个嵌套的分类法,例如,我想将属于同一概念实体(“Hexa”、“Hex”)的所有术语识别为“Hexagon”。 我无法弄清楚如何使用 PhraseMatcher 来做到这一点,或者使用其他方法是否更好。

提前感谢您的任何建议。

###更新 按照建议我修改了代码:

ruler = nlp.add_pipe("entity_ruler")
patterns = [{"label": "MAT_TYPE", "pattern": [{"LOWER": "screw"}], "id": "Screw"},
            {"label": "MAT_TYPE", "pattern": [{"LOWER": "bolt"}], "id": "Bolt"},
           {"label": "MAT_TYPE", "pattern": [{"LOWER": "washer"}], "id": "Washer"},
           {"label": "ISO", "pattern": [{"TEXT": "4014"}, {"TEXT": "4014-8.8"}], "id": "4014"},
            {"label": "ISO", "pattern": [{"LOWER": "4017-8.8"}], "id": "4017"},
           {"label": "ISO", "pattern": [{"LOWER": "7040"}, {"LOWER": "7040-8"}], "id": "7040"}]
ruler.add_patterns(patterns)
with open('./sample_list.txt', 'r') as infile:
    data = infile.readlines()
    for i in data:
        print(i)
        doc = nlp(i.lower())        
        print([(ent.text, ent.label_, ent.ent_id_) for ent in doc.ents])

似乎完全符合我的需要,只是我无法检测到文本 (ISO) 中包含的标签:

[('washer', 'MAT_TYPE', 'Washer')]
Hexagon head bolt M12x80 ISO 4014-8.8-Geomet 321A+VL

[('bolt', 'MAT_TYPE', 'Bolt')]
Hexagon head bolt M12x90 ISO 4014-8.8-Geomet 321A+VL

[('bolt', 'MAT_TYPE', 'Bolt')]
Hexagon head bolt M20x90 ISO 4014-8.8-Geomet 321A+VL

听起来您希望能够将元数据添加到匹配项中,以识别方案中相同的内容。为此,您应该使用 EntityRuler 查看 adding IDs to match patterns。这是来自 spaCy 文档的示例:

from spacy.lang.en import English

nlp = English()
ruler = nlp.add_pipe("entity_ruler")
patterns = [{"label": "ORG", "pattern": "Apple", "id": "apple"},
            {"label": "GPE", "pattern": [{"LOWER": "san"}, {"LOWER": "francisco"}], "id": "san-francisco"},
            {"label": "GPE", "pattern": [{"LOWER": "san"}, {"LOWER": "fran"}], "id": "san-francisco"}]
ruler.add_patterns(patterns)

doc1 = nlp("Apple is opening its first big office in San Francisco.")
print([(ent.text, ent.label_, ent.ent_id_) for ent in doc1.ents])

doc2 = nlp("Apple is opening its first big office in San Fran.")
print([(ent.text, ent.label_, ent.ent_id_) for ent in doc2.ents])

在本例中 san-francisco 是一个 ID,但您可以添加像 head-hex 这样的 ID 来识别您的模式中“六边形”的所有变体。

请注意,我会将您尝试做的事情称为规范化,或者可能是细粒度实体标签,而不是创建分类法。我不确定“嵌套分类法”是什么意思,我猜你的意思是你的标签是嵌套的?就像你有一个“头”,然后在“头”中你有不同的类别,如“hex”或“phillips”。

如果您提供更多所需输出类型的示例,可能会有所帮助。


你的模式没有得到你的 ISO 模式的问题可能是因为像 4014-8.8 这样的东西最终变成了多个标记。将您的模式更改为:

{"label": "ISO", "pattern": "4017-8.8", "id": "4017"}

当您传递一个字符串时,spaCy 会为您计算出标记化。

由于此处的模式只是数字,所以没关系,但如果您确实需要匹配 LOWER 属性,请查看 matching on other attributes.

上的文档