spaCy 的 nlp 对象需先通过 spacy.load() 加载模型(如 "zh_core_web_sm")才能使用,不可直接调用;中文词形还原无效,应关注 token.text、pos_、tag_;切片返回 Span 而非 Token,类型需区分;禁用无关 pipeline 组件可提升词性标注稳定性。

spaCy 的 nlp 对象必须先调用才能分词
很多人写完 import spacy 就直接对字符串调 nlp("hello"),结果报错 NameError: name 'nlp' is not defined。这不是语法问题,是漏了模型加载步骤。
spaCy 不像 NLTK 那样自带轻量分词器,它必须显式加载语言模型——哪怕只是基础分词和词性标注,也得走一遍 spacy.load()。
-
nlp = spacy.load("zh_core_web_sm")(中文)或nlp = spacy.load("en_core_web_sm")(英文),模型名必须准确,大小写、下划线都不能错 - 首次运行会自动下载模型,如果网络受限,可提前用
python -m spacy download zh_core_web_sm安装 - 别用
spacy.blank("zh")代替——它没内置词汇表和词性规则,token.pos_全是""
分词结果里 token.text 和 token.lemma_ 别混用
中文场景下 token.lemma_ 基本无效,但很多人仍习惯性打印它,结果全是原词或空字符串。spaCy 的词形还原(lemmatization)严重依赖词性标注,而中文缺乏屈折变化,官方模型对中文的 lemma_ 支持极弱。
真正该关注的是 token.text(原始切分结果)、token.pos_(粗粒度词性,如 NOUN、VERB)、token.tag_(细粒度标签,如 NN、VV)。
立即学习“Python免费学习笔记(深入)”;
- 中文分词质量取决于模型训练语料,
zh_core_web_sm在短句、专有名词上容易切错,比如把“微信支付”拆成“微信”“支付”而非整体识别为PROPN - 若需更高精度,可加规则:用
nlp.add_pipe()插入自定义组件,匹配常见词组后设token._.is_sentinel = True并跳过后续处理 -
token.is_punct、token.is_space这类布尔属性比正则判断更可靠,避免手动过滤标点时漏掉全角符号
doc 对象不是 list,但支持索引和切片
拿到 doc = nlp("今天天气不错") 后,想取前两个词,别写 doc[0:2].text 报错说 'Span' object has no attribute 'text'——因为切片返回的是 Span,不是 Token。
Span 有 .text,但没有 .pos_;单个 Token 才有完整词性信息。这个类型混淆在循环处理时特别容易踩坑。
- 遍历每个词用
for token in doc:,安全获取token.text和token.pos_ - 要取子句(比如主谓宾结构),用
doc[1:4]得到Span,再用span.text拿文本,但词性得单独从每个token读 - 别对
doc直接用len()判断是否为空——空字符串返回空Doc,len(doc)是 0,但doc本身不为None,判空请用if doc:
中文词性标注不准?先关掉 disable 以外的 pipeline 组件
默认加载的模型带 parser、ner 等组件,它们会互相影响中文的 pos_ 输出。比如开启命名实体识别(NER)后,“苹果”在“吃苹果”里可能被强行标成 PROPN(因同时出现在“苹果公司”语境中)。
如果只要分词+词性,启动时显式禁用无关组件能提升稳定性:
import spacy
nlp = spacy.load("zh_core_web_sm", disable=["parser", "ner", "textcat"])
注意:disable 参数必须传列表,不能传字符串;禁用 parser 后 token.dep_ 会变空,但 pos_ 反而更贴近分词本意。
- 如果后续还要做依存分析,就别禁用
parser,但得接受词性偶尔妥协于句法结构 -
zh_core_web_sm的词性体系基于 UD(Universal Dependencies),和传统汉语语法术语不完全对应,比如“了”标为AUX而非“助词” - 调试时打印
[(t.text, t.pos_, t.tag_) for t in doc]比只看doc字符串更直观
pos_ 是否“正确”,不如先确认 pipeline 配置和输入文本的规范性。


















