做文本分析时,选对工具往往能省掉一半的工作量。Python生态里,NLTK和spaCy是最常被拿来做自然语言处理(NLP)的两个库,但很多初学者在两者之间摇摆不定:一个功能全面但速度偏慢,一个高效快速但定制性稍弱。这篇文章会带你从零开始,用实际的代码把这两个库的核心功能跑一遍,最后再给出选型建议,让你面对具体项目时心里有底。

环境准备与基础概念
在动手之前,先把两个库装好。NLTK的安装很简单,直接用pip即可,但装完之后还需要下载它的语料库和模型资源,这一点经常被新手忽略,导致代码跑到一半报错。
pip install nltk
pip install spacy
# 下载NLTK常用资源
import nltk
nltk.download('punkt') # 分词模型
nltk.download('averaged_perceptron_tagger') # 词性标注器
nltk.download('stopwords') # 停用词表
nltk.download('wordnet') # 词汇数据库
# 下载spaCy英文模型
# 命令行执行:python -m spacy download en_core_web_sm装好之后需要理解一个基本概念:自然语言处理的第一步几乎都是把连续的文本切分成一个个有意义的单元,这个过程叫分词(Tokenization)。英文按空格切分看起来容易,但遇到"don't"、"New York"这类情况就复杂了,所以需要专门的分词器。中文更麻烦,词与词之间没有空格,需要借助jieba这类分词库配合处理。本文以英文为主,中文场景会在后面单独提一下。
另外要区分两个容易混淆的概念:词干提取(Stemming)和词形还原(Lemmatization)。前者用粗暴的规则截断词尾,比如studies变成studi,速度快但结果可能不是合法单词;后者基于词典和上下文,把studies还原成study,准确但更耗资源。NLTK对两者都支持,spaCy则只提供词形还原,这也是两个库设计理念差异的体现。
NLTK核心功能实战
NLTK诞生于学术圈,历史超过二十年,最大的特点是功能模块拆得很细,适合学习和做研究。先看最基础的分词和词性标注。
from nltk.tokenize import word_tokenize, sent_tokenize
from nltk import pos_tag
text = "Apple is looking at buying U.K. startup for $1 billion. Dr. Smith approved it."
# 句子切分
sentences = sent_tokenize(text)
print(sentences)
# 输出:['Apple is looking at buying U.K. startup for $1 billion.', 'Dr. Smith approved it.']
# 单词切分
tokens = word_tokenize(text)
print(tokens[:8])
# 输出:['Apple', 'is', 'looking', 'at', 'buying', 'U.K.', 'startup', 'for']
# 词性标注
tagged = pos_tag(tokens)
print(tagged[:4])
# 输出:[('Apple', 'NNP'), ('is', 'VBZ'), ('looking', 'VBG'), ('at', 'IN')]注意上面U.K.和Dr.没有被错误切开,这就是专用分词器的价值。如果直接用Python的split方法,标点会黏在单词上,后续统计词频时会出现大量脏数据。
接下来是停用词过滤和词形还原,这两个操作在做文本分类、情感分析前几乎是必做的预处理步骤。停用词指的是is、the、a这类高频但几乎没有信息量的词,过滤掉它们能让特征更干净。
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
stop_words = set(stopwords.words('english'))
lemmatizer = WordNetLemmatizer()
filtered = [w for w in tokens if w.lower() not in stop_words and w.isalpha()]
lemmas = [lemmatizer.lemmatize(w) for w in filtered]
print(lemmas)
# 输出类似:['Apple', 'looking', 'buying', 'U.K.', 'startup', 'billion', 'Dr.', 'Smith', 'approved']这里有个细节值得注意:lemmatize方法默认按名词处理,如果想让动词还原得准确,需要传入词性参数,比如lemmatizer.lemmatize('running', pos='v')会得到run,而默认调用会原样返回running。正确做法是先做词性标注,再把词性映射到WordNet的标签体系后再还原,虽然步骤多,但精度确实高。
NLTK还内置了命名实体识别(NER),能识别出人名、地名、机构名等:
from nltk import ne_chunk
entities = ne_chunk(pos_tag(word_tokenize("Apple is looking at buying U.K. startup.")))
print(entities)
# 会以树结构输出:Apple(ORGANIZATION)、U.K.(GPE)等实体标签ne_chunk返回的是嵌套树结构,遍历起来不算方便,而且准确率在真实语料上表现一般。如果你的项目对实体识别要求高,就应该考虑spaCy了。
spaCy核心功能实战
spaCy是工业级设计的代表,它的核心思路是:一次调用nlp处理整段文本,分词、词性、依存句法、实体识别全部在一条流水线里完成,不需要像NLTK那样逐个模块拼接。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K. startup for $1 billion.")
# 一次遍历拿到全部信息
for token in doc:
print(token.text, token.lemma_, token.pos_, token.is_stop)
# 命名实体识别
for ent in doc.ents:
print(ent.text, ent.label_)
# 输出:
# Apple ORG
# U.K. GPE
# $1 billion MONEY对比NLTK的ne_chunk,spaCy把Apple正确识别为ORG(机构),还把$1 billion整体识别为MONEY,准确率明显更高。而且spaCy的词形还原是基于规则加上下文的,无需手动指定词性,token.lemma_直接给出结果。
spaCy的另一个杀手锏是依存句法分析,可以拿到词与词之间的语法关系:
for token in doc:
print(token.text, token.dep_, token.head.text)
# looking是句子核心词,Apple是它的主语,buying是它的宾语从句部分
# 这种结构对信息抽取、问答系统非常有用性能方面,spaCy用Cython实现了核心计算,处理速度通常是NLTK的5到10倍。在批量处理大规模语料时,这个差距会被急剧放大。可以简单做个测试:处理一万条英文句子,NLTK走完分词加标注可能需要十几秒,spaCy用nlp.pipe()批量接口往往两三秒就能跑完,而且信息还更丰富。
texts = ["Example sentence number %d." % i for i in range(10000)] # spaCy批量处理,禁用不需要的组件还能更快 docs = list(nlp.pipe(texts, disable=["parser"]))
另外,spaCy对中文也有官方模型支持(zh_core_web_sm),配合其内置的中文分词器可以直接处理中文文本,不必额外引入jieba。不过中文模型的效果依赖训练语料,特定领域建议用自己的数据微调。
如何选择:场景决定工具
两个库没有绝对的优劣,关键看你的使用场景。可以从三个维度来判断。
第一,学习与研究场景选NLTK。它的模块化设计让你能清楚看到每一步在做什么,方便理解算法原理,写论文做实验、对比不同分词器或标注器的效果时非常合适。NLTK还附带大量语料库和教材配套资源,是学习NLP理论的好帮手。
第二,生产环境和大数据量选spaCy。速度优势明显,API统一,实体识别和依存分析精度更高,模型还支持深度学习定制训练。如果你的产品需要实时处理用户输入的文本,spaCy几乎是默认选择。
第三,两者混用也完全没问题。常见的组合方式是:用NLTK做教学演示或预处理实验,确定方案后用spaCy重写上线;或者用NLTK的语料库资源配合spaCy的模型能力,各取所长。
中文处理的一点补充
如果主要处理中文,NLTK的中文支持比较弱,spaCy的中文模型能用但精度一般。实践中更常见的方案是jieba分词加自定义词典,做情感分析再配合SnowNLP,做深度学习方案则可以直接上 transformers 预训练模型。中文NLP的难点在于分词歧义和未登录词,jieba的HMM模型和用户词典机制能解决大部分问题:
import jieba
# 添加自定义词,避免专有名词被切碎
jieba.add_word("自然语言处理")
words = jieba.lcut("自然语言处理是人工智能的重要方向")
print(words)
# 输出:['自然语言处理', '是', '人工智能', '的', '重要', '方向']总的来说,先把NLTK和spaCy的英文流程跑通,理解分词、词性、实体这些基础概念,再迁移到中文工具链上,学习曲线会平缓很多。文本处理本身是个熟能生巧的活,多拿真实数据练手,比看十篇教程都有用。
Python自然语言处理NLTKspaCy修改时间:2026-09-13 03:46:35