1. 为什么我每次做中文文本分析,第一步都是先处理停用词
做中文文本分析的朋友大概都有过这样的经历:兴致勃勃用Python跑完一段jieba分词,打印出结果一看,满屏都是"的"、"了"、"是"、"在"这类词,真正有价值的关键词反而被淹没在里面。
我之前处理一批用户评论数据的时候,想统计大家高频提到的话题词,第一次分词完直接做词频统计,排在最前面的居然全是"这个"、"那个"、"就是"、"觉得"这种词,完全没法用。后来才意识到,这一步缺了停用词过滤。
停用词(stopwords)指的就是那些在文本中频繁出现、但对理解文本主旨帮助不大的词,比如语气词、助词、介词、连词,还有大量泛化的代词和口语词。这些词单独拎出来没有任何语义指向,堆在词频统计结果里纯粹是噪音。
这篇文章就把我这些年积累的中文停用词处理经验完整梳理一遍,包括常用停用词表、如何自己扩充停用词、以及一套可以直接套用的Python分词+停用词过滤流程。适合刚开始做文本挖掘、词频统计、舆情分析的Python使用者,也适合那些已经跑通了分词但结果始终不理想的朋友。
以一条"这家店的奶茶真的太好喝了,口感很丝滑,下次还会再来"为例,不用停用词直接分词,结果是:
这家店 / 的 / 奶茶 / 真的 / 太 / 好喝 / 了 / , / 口感 / 很 / 丝滑 / , / 下次 / 还会 / 再来过滤掉停用词(的、了、很、太、还会、真的等)之后,剩下的核心词是:
奶茶 / 好喝 / 口感 / 丝滑 / 下次 / 再来两者的信息密度差距一眼就能看出来。
2. 停用词表从哪来:三大来源和一份可直接用的基础表
2.1 现成的停用词表资源
停用词表不需要从零发明,业内已经积累了很多公开可用的词表,最常用的有三个方向:
- 哈工大停用词表:覆盖面很广,偏学术和正式场景,包含近2000个词。
- 百度停用词表:更贴近互联网语料,口语词、网络词比较多。
- 中文停用词表(四川大学):综合性比较好,适合通用场景。
我平时的做法是把这几份词表下载下来,合并去重,再根据自己的数据特点做增删。GitHub上搜"中文停用词表"能找到很多现成仓库,注意挑选star高、更新活跃的。
2.2 不要迷信现成词表
这里我想强调一个观点:现成停用词表只是起点,不是终点。
因为不同领域的"停用词"差异很大。比如在一篇讲手机评测的文章里,"手机"这个词出现频率极高,但对"这个领域"做特征分析时,"手机"可能是核心主题词而不是噪音;反过来,在做"电商评论情感分析"的时候,"好评"、"差评"这种词频繁出现,也可能需要根据场景单独处理。
所以我把停用词分成两类:
- 通用停用词:任何场景都该过滤的词(的、了、啊、呢、和、与、就、都等)
- 领域停用词:只在当前分析场景下属于噪音的词(如"这家店"、"这边"、"感觉"等口语空泛词)
我通常先加载通用词表,再根据实际分词结果手动补充领域停用词。
2.3 一份可以直接用的基础停用词表
下面这份词表是我从多个公开词表中整理合并的精华版本,涵盖最常用的一批,直接用Python列表展示:
base_stopwords = [ # 助词/语气词 "的", "了", "着", "过", "吧", "啊", "呢", "吗", "哦", "哈", "呀", "嘛", "呗", "而已", "罢了", "啦", "喽", # 代词/指代词 "我", "你", "他", "她", "它", "我们", "你们", "他们", "她们", "它们", "这", "那", "这个", "那个", "这些", "那些", "这里", "那里", "这样", "那样", "这么", "那么", "什么", "怎么", "怎样", "如何", "谁", "哪儿", "哪里", "为什么", "几", "多少", # 介词/连词 "在", "和", "与", "及", "或", "而", "且", "但", "但", "然而", "不过", "虽然", "因为", "所以", "如果", "即使", "尽管", "按照", "根据", "关于", "对于", "除了", "通过", "经过", # 副词/程度词 "很", "太", "非常", "十分", "特别", "最", "更", "都", "只", "就", "也", "还", "又", "再", "已", "曾经", "正在", "立刻", "马上", "逐渐", "偶尔", "总是", "往往", "常常", # 泛化动词 "是", "有", "到", "去", "来", "做", "干", "说", "看", "听", "买", "卖", "能", "可以", "应该", "需要", "觉得", "认为", "知道", "发现", "希望", "想", "要", "会", # 时间泛化词 "今天", "明天", "昨天", "现在", "之前", "之后", "时候", "时间", "以后", "以前", "目前", "当时", # 口语填充词 "然后", "就是", "一个", "那种", "这种", "反正", "其实", "感觉", "真的", "有点", "这个", "那个", "一下", "的话", ]提示:这份词表不涉及任何特定产品、公司或机构,就是一份通用汇总,可以直接存成txt文件,每行一个词,后续加载使用。
3. 手把手搭一套jieba分词+停用词过滤的完整流程
3.1 环境准备
需要安装的库就两个:
pip install jieba不需要额外安装停用词库,直接加载本地词表文件就行。
3.2 核心代码:加载停用词表
写一个最常用的加载函数:
def load_stopwords(path="stopwords.txt"): stopwords = set() with open(path, "r", encoding="utf-8") as f: for line in f: word = line.strip() if word and word not in stopwords: stopwords.add(word) return stopwords这里用set而不是list,因为判断词是否在停用词表里这个操作会被执行成千上万次,set的查找复杂度是O(1),list是O(n)。数据量大的时候,这个差距很可观。
3.3 核心代码:分词与过滤
import jieba def seg_and_filter(text, stopwords): # jieba.lcut直接返回列表 words = jieba.lcut(text) filtered = [] for w in words: w = w.strip() # 过滤空字符串、纯空格 if not w: continue # 过滤停用词 if w in stopwords: continue # 过滤单个字(英文单字母、无意义单字) if len(w) < 2: continue filtered.append(w) return filtered我一般还建议额外加一条规则:过滤掉纯标点和只包含一个字符的token。因为中文里很多单字如果不加筛选,会出现"好"、"坏"、"难"这类高情绪单字——这个按需取舍,如果想保留就删掉len(w) < 2这个判断。
3.4 完整示例:对一个文档做分词和词频统计
这里给出一段可以直接跑的完整代码,输入是一段文本列表,输出是过滤后的高频词Top20:
import jieba from collections import Counter stopwords = load_stopwords("stopwords.txt") docs = [ "这家店的奶茶真的太好喝了,口感很丝滑,下次还会再来", "奶茶味道不错,但是排队太久了,服务态度一般", "珍珠奶茶yyds,奶盖很香,推荐大家试试", ] counter = Counter() for doc in docs: words = seg_and_filter(doc, stopwords) counter.update(words) top_words = counter.most_common(20) for word, count in top_words: print(f"{word}\t{count}")实际输出效果大致如下(根据分词结果略有差异):
奶茶 3 口感 1 丝滑 1 下次 1 再来 1 味道 1 不错 1 排队 1 太久 1 服务态度 1 珍珠 1 yyds 1 奶盖 1 推荐 1 大家 1 试试 1对比不过滤停用词时"的"、"了"、"真的"霸榜的局面,这个结果已经干净多了。
3.5 关于中文分词的自定义词和词典加载
jieba的分词效果在通用场景已经不错,但遇到专业词汇和网络新词,还是会切错。比如"奶盖"这种词,如果不加自定义词典,可能被切成"奶"和"盖"。
可以在项目目录放一个userdict.txt,每行一个词,格式如下:
奶盖 3 n yyds 3 n 珍珠奶茶 3 n然后加载:
jieba.load_userdict("userdict.txt")那个数字3代表词频权重,n是词性标注(可省略)。这个权重设置越大,该词被合并的概率越高,一般建议用2或3就够了,太大了容易误合并。
4. 那些年我踩过的坑:停用词处理不彻底导致的三个典型事故
4.1 事故一:标点和空白字符没过滤干净
有一次做词云图,生成出来的图片里全是逗号、句号、冒号,排查了半天才发现是分词结果里标点符号没有被当成停用词过滤掉。
解决方式很简单,分词后统一判断一下是否含有中英文标点:
import re def is_valid_word(w): if re.fullmatch(r"[a-zA-Z0-9]+", w): # 纯英文或数字 return len(w) >= 2 # 至少2个字符 if re.fullmatch(r"[\u4e00-\u9fff]+", w): # 纯中文 return len(w) >= 2 return False # 含标点、特殊字符的token直接丢弃这样"yyds"能保下来,但"……"、"——"、"好的,"这种含标点的碎片会直接扔掉。
4.2 事故二:把"有语义的领域词"误杀了
最开始我图省事,把一份网上找的停用词表全部加载,结果发现"手机"、"电脑"这种词也被过滤掉了。仔细一看才发现那份词表里把大量名词也放了进去,导致核心主题词被误删。
所以现在我的做法是:
- 通用停用词表,只保留确定无意义的词;
- 领域停用词表,单独维护,针对每次任务定制;
- 每次加载后先跑几条样例,肉眼看过滤结果,再决定增删。
4.3 事故三:jieba的重引擎模式和搜索模式搞混
jieba有三种分词模式:精确模式(默认)、全模式、搜索引擎模式。很多新手用jieba.cut(text, cut_all=True)拿全模式的结果做词频统计,出来的词碎片化严重,比如"奶茶"被拆成"奶茶"和"茶"两个词。
做词频统计,正确姿势是使用默认的精确模式,也就是jieba.lcut(text),不需要设置cut_all=True。搜索引擎模式则适合在检索场景召回更多相关词,不适合做词频统计。
5. 进阶玩法:停用词处理其实不只是"删词"
5.1 停用词还能拿来清洗数据
除了分词后过滤,停用词表也可以用于文本预处理阶段。比如从网页抓下来的文本包含大量"您好"、"欢迎访问"、"点击查看"这类导航和问候内容,这些虽然不是严格意义上的停用词,但在这个场景下同样是噪音。把这类词加入停用词表,在分词阶段一并过滤,文本质量会提升很多。
5.2 结合TF-IDF进一步压制通用词
如果做的是关键词提取,光靠停用词还不够,因为"奶茶"、"口感"这种词在单篇文档里出现频率再高,在整个语料里如果到处都是,也不是好区分的关键词。
推荐用jieba.analyse.extract_tags,它内部做了TF-IDF计算,天然会对高频通用词降权:
import jieba.analyse text = "这家店的奶茶真的太好喝了,口感很丝滑,下次还会再来" keywords = jieba.analyse.extract_tags(text, topK=5, withWeight=True) print(keywords)它会返回带权重的关键词列表,比单纯的词频统计更能挑出有区分度的词。不过我实际用下来感觉,它用的默认IDF语料偏新闻领域,如果你处理的是特定行业文本(如电商、医疗、法律),建议自己准备好语料后,用自定义IDF做权重计算。
5.3 在情感分析里,停用词的取舍逻辑完全不同
前面说的都是词频统计场景,做情感分析时"太"、"很"这类程度副词反而是重要信号。"太好喝了"和"好喝"的情感强度明显不同。
所以别把"停用词"当成一个固定的概念。做主题聚类、词云、词频统计时,大量虚词需要过滤;做情感分析时,恰恰要保留程度词、否定词,它们是最关键的判别依据。这也是我每次都单独建停用词表、不搞"一份词表跑天下"的原因。
6. 工作效率小技巧:批量测试和停用词可视化检查
调试停用词表是个迭代过程,千万别一句一句手动验证。我习惯写一个小脚本,批量跑几十条样本,把过滤后的结果打印出来快速浏览:
def quick_test(docs, stopwords): for idx, doc in enumerate(docs[:20]): words = seg_and_filter(doc, stopwords) print(f"--- 样本{idx + 1} ---") print("原始:", doc) print("过滤后:", " / ".join(words)) print()跑一遍就能发现:
- 还有哪些高频噪音词没被过滤;
- 哪些不该被过滤的词被误删了;
- jieba哪些词切得不合理,需要加自定义词典。
这个过程通常迭代三四次就能得到一个质量不错的词表。多花这十几分钟的肉眼检查,比事后反复调代码高效得多。
另外,如果做的是英文文本分析,思路完全一样,只是英文停用词直接用nltk.corpus.stopwords.words('english')就行,中文没有特别统一的开箱即用方案,所以才需要花时间自己积累词表。这也是为什么这类停用词分享在中文文本分析圈子里一直有需求。
7. 一点收尾分享:词表维护的习惯
我在项目里把停用词表单独放在data/stopwords.txt,然后在代码仓库里建了一个docs/stopwords_changelog.md,每次增删词都记录一句原因。看起来有点多此一举,但有一次项目做了半年,引擎换了,数据处理流程重跑,那些当初加的词为什么加、为什么需要保留,如果没有记录就得全部重新摸一遍。
词表这事,看起来是个体力活,实际上是个细心活。你保存下来的每一个词,都是对一批真实数据的理解。把这些理解沉淀下来,后续再做同类分析,会越跑越顺。