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

如何基于Token属性快速过滤Spacy Doc对象并保留原标注信息

快速过滤Spacy Doc对象并保留标注信息的方法

核心思路

不用拆分重建Doc,直接基于原Doc的Token集合做过滤,要么生成保留原属性的Token列表,要么按需构建带完整标注的新Doc,比拆成单词再重建高效得多。


方法1:直接生成过滤后的Token列表(最快最实用)

Spacy的Doc不可变,但你可以直接筛选符合条件的Token,这些Token会保留所有原标注(POS、NER、lemma等),完全满足需求。逻辑和你之前用Pipe处理普通单词的逻辑对应:

import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("The quick brown fox jumps over the lazy dog.")

# 按你的Pipe规则过滤,保留原Token对象(方便访问标注)
filtered_tokens = [
    token
    for token in doc
    if 3 <= len(token.text) <= 15  # size(3,15)
    and token.is_alpha  # is_word
    and not token.is_stop  # isnt_stop
]

# 如果需要直接拿到处理后的字符串(lwcase + lemma)
filtered_lemmas = [token.lemma_.lower() for token in filtered_tokens]

# 直接访问原标注信息
for token in filtered_tokens:
    print(f"文本:{token.text},词性:{token.pos_},实体类型:{token.ent_type_}")

这个方法零额外开销,不用修改原Doc,所有标注信息都在原Token里,是最推荐的方案。


方法2:重建带完整标注的新Doc(仅当必须用Doc格式时)

如果业务逻辑要求必须输出Doc对象,而不是Token列表,可以用以下两种方式:

方式A:用Doc.from_docs快速生成(Spacy v3+支持)

这个方法会自动复制Token的大部分属性,操作简单:

# 从过滤后的Token生成新Doc
filtered_docs = [token.doc for token in filtered_tokens]
new_doc = spacy.tokens.Doc.from_docs(filtered_docs)

# 验证标注
for token in new_doc:
    print(f"文本:{token.text},lemma:{token.lemma_},词性:{token.pos_}")

方式B:手动复制所有标注(精确控制)

如果需要保留NER等跨度级别的标注,手动构建并复制属性更稳妥:

# 用原Doc的词汇表创建新Doc
new_doc = spacy.tokens.Doc(nlp.vocab, words=[t.text for t in filtered_tokens])

# 逐个复制Token级标注
for i, old_token in enumerate(filtered_tokens):
    new_token = new_doc[i]
    new_token.pos_ = old_token.pos_
    new_token.lemma_ = old_token.lemma_
    new_token.is_stop = old_token.is_stop
    # 其他需要的属性(如tag_、dep_)都可以这样复制

# 复制NER实体信息
new_ents = []
for ent in doc.ents:
    # 检查实体的所有Token是否都在过滤列表中
    if all(t in filtered_tokens for t in ent):
        # 找到实体在新Doc中的起始/结束索引
        start_idx = filtered_tokens.index(ent[0])
        end_idx = start_idx + len(ent)
        new_ents.append(spacy.tokens.Span(new_doc, start=start_idx, end=end_idx, label=ent.label_))
new_doc.ents = new_ents

# 查看结果
print("新Doc的实体:", new_doc.ents)

为什么不推荐用spacy-pipelines?

你提到的逐个用spacy-pipelines确实没必要,因为Pipeline组件是针对整个Doc做全局处理的,而你需要的是基于单个Token属性的细粒度过滤,用列表推导直接筛选Token是最直接高效的,逻辑也和你之前的Pipe操作完全对齐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:27:27