You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于已分词并关联Gold标注的BILUO格式数据集,使用spaCy实现回溯分句并同步gold.sent_starts

回溯拆分BILUO格式数据集并同步句子边界与Gold标注

我来帮你搞定这个分句同步的问题——核心就是把spaCy分句后的句子边界,和你已经生成的tokens、BILUO标签,以及Gold数据里的sent_starts标记精准对齐。下面是分步的解决方案和代码示例:

关键思路

你已经有了带BILUO标签的token级数据,现在需要:

  1. 用spaCy的分句器对原始文档分句,得到每个句子的token索引范围;
  2. 基于这些索引,把token列表、NER标签和Gold的sent_starts数组按句子拆分;
  3. 确保拆分后的每个句子的句首标记和分句结果一致(避免Gold标注可能存在的偏差)。

具体实现代码

首先调整你的spaCy流水线,只保留分句器(避免默认parser的干扰,让分句规则更可控),然后修改处理循环:

# 初始化spaCy,禁用不需要的组件,只保留分句器
nlp = spacy.load('de_core_news_sm', disable=['ner', 'parser'])
nlp.add_pipe("sentencizer")

# 遍历你的原始数据集(docs是文本列表,golds是经典spaCy格式的标注字典列表)
for idx, (doc_text, gold_data) in enumerate(zip(docs, golds)):
    # 1. 用带分句器的流水线处理文本,得到带句子边界的doc对象
    doc = nlp(doc_text)
    
    # 2. 生成GoldParse对象,对齐原始标注(这里用gold_data里的entities)
    gold = GoldParse(doc, entities=gold_data["entities"])
    
    # 3. 提取每个句子的token起始/结束索引
    sentence_ranges = [(sent.start, sent.end) for sent in doc.sents]
    
    # 4. 按句子拆分样本,同步所有相关数据
    split_samples = []
    for start_idx, end_idx in sentence_ranges:
        # 提取当前句子的文本、tokens、NER标签
        sent_text = doc[start_idx:end_idx].text
        sent_tokens = [token.text for token in doc[start_idx:end_idx]]
        sent_ner_tags = gold.ner[start_idx:end_idx]
        
        # 提取并修正sent_starts:确保当前句子的第一个token标记为句首
        sent_sent_starts = gold.sent_starts[start_idx:end_idx].copy()
        sent_sent_starts[0] = True  # 强制分句结果的句首为True,避免Gold标注的不一致
        
        split_samples.append({
            "text": sent_text,
            "spacy_tokens": sent_tokens,
            "ner_tags": sent_ner_tags,
            "sent_starts": sent_sent_starts
        })
    
    # 这里可以将split_samples存入新的数据集,或者做后续处理
    print(f"处理完第{idx}个样本,拆分为{len(split_samples)}个句子")

重要细节说明

  • 为什么用sentencizer而不是默认parser?
    默认的spaCy parser会依赖句法分析来分句,可能和你原始标注的句子边界逻辑不一致。sentencizer是基于规则的分句器(比如按句号、感叹号等),更适合回溯性拆分已标注的数据集,避免引入额外的句法分析偏差。

  • 同步Gold的sent_starts
    GoldParse的sent_starts是一个布尔数组,每个元素对应一个token是否是句子开头。拆分时我们强制每个子句的第一个token为True,这是为了确保分句结果和标记的一致性——如果原始Gold标注的sent_starts和分句结果有冲突,优先以实际分句后的边界为准(你也可以根据需求调整,比如保留原始Gold标记,但需要额外处理冲突情况)。

  • 如果原始Gold数据包含sent_starts?
    如果你的golds字典里本身有sent_starts字段,只需在生成GoldParse时传入:

    gold = GoldParse(doc, entities=gold_data["entities"], sent_starts=gold_data["sent_starts"])
    

    拆分逻辑保持不变即可。

内容的提问来源于stack exchange,提问作者tenticon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:02:30