如何为SpaCy Doc对象分配自定义IOB标签并用DisplaCy可视化
适配逐词IOB标签的修改方案
你现在已经有和Doc词粒度完全对齐的IOB标签,不需要再用字符跨度匹配,直接遍历IOB列表合并连续的同实体标签,生成对应词跨度的实体即可,修改后的完整代码如下:
import spacy from spacy import displacy def Visualizer(file_name, path, iob_tags): nlp = spacy.blank("fa") # 改用with open避免文件句柄泄漏 with open(f"{path}/{file_name}.txt", 'r', encoding='utf-8') as f: raw_text = f.read() doc = nlp.make_doc(raw_text) ents = [] # 记录当前正在拼接的实体的起始词索引和实体类型 current_ent_start = None current_ent_label = None for idx, tag in enumerate(iob_tags): if tag.startswith("B-"): # 遇到新的实体起始标签,先把上一个未收尾的实体存入列表 if current_ent_start is not None: ent_span = doc[current_ent_start:idx] ents.append(ent_span) # 初始化新实体的参数 current_ent_start = idx current_ent_label = tag.split("-")[1] elif tag.startswith("I-"): # 同类型的I标签直接延续当前实体,标签不匹配的话直接结束上一个实体 if current_ent_label != tag.split("-")[1]: if current_ent_start is not None: ent_span = doc[current_ent_start:idx] ents.append(ent_span) current_ent_start = None current_ent_label = None elif tag == "O": # 遇到非实体标签,结束当前正在拼接的实体 if current_ent_start is not None: ent_span = doc[current_ent_start:idx] ents.append(ent_span) current_ent_start = None current_ent_label = None # 处理文档末尾还没收尾的实体 if current_ent_start is not None: ent_span = doc[current_ent_start:len(doc)] ents.append(ent_span) doc.ents = ents displacy.render(doc, style="ent", jupyter=True) # 调用示例,替换为你自己的IOB标签列表即可 your_iob_tags = ['O', 'B-PER', 'I-PER', 'O', 'O', 'O', 'O', 'B-DATE', 'I-DATE', 'I-DATE', 'I-DATE', 'I-DATE', 'O', 'O', 'O', 'O', 'O', 'B-ORG', 'I-ORG'] visualized_data = Visualizer('test', path, your_iob_tags)
核心修改说明
- 新增
iob_tags入参,传入你提前准备好的、和Doc词长度完全对齐的IOB标签列表 - 移除原有的字符跨度遍历逻辑,替换为IOB标签合并逻辑,直接通过词索引生成实体跨度,不需要再做字符位置匹配
- 增加了边界兼容逻辑,即使IOB标签存在不规范的情况(比如I标签没有对应B标签)也能正常运行
内容的提问来源于stack exchange,提问作者BlueBlue
相关产品推荐
相关产品推荐

