
简介这份中英文停用词资源包面向从事文本分析、自然语言处理与信息检索的开发者及研究者用于解决分词后噪声词干扰关键词提取与情感判断的问题。包内共11个文件以9个txt停用词表和2个py脚本为主压缩包约45KB体积轻便却覆盖中文、英文及中英合并等多套词表脚本可用于合并与统一不同来源的词表方便按需定制。已有1220人学习下载说明其在文本预处理场景中具有一定参考价值。读者可直接将词表接入jieba或nltk等分词工具在分词后过滤助词、介词、连词、冠词等高频低信息量词汇从而提升关键词抽取、文本分类与情感分析的准确度同时可参考脚本思路结合具体语料定期扩充和更新停用词库应对网络新词带来的变化。1. 史上最全中英文停用词为什么你的关键词提取总在“的、了、是”上翻车做文本挖掘的同行大概率都经历过这个场景TF-IDF 跑完权重最高的词是“我们”“可以”“进行”LDA 主题模型出来的结果每个主题里都混着“的”“了”“和”关键词抽取工具给出的 Top10 里一半是虚词。这不是算法不行是停用词表没管住。停用词stopwords指的是在信息检索和文本挖掘中高频出现、但几乎不携带语义区分度的词中文里像“的、了、是、在、和、就”英文里像 the、is、at、which、on。它们的作用是让句子通顺但对“这段话在讲什么”几乎没有贡献。所谓“史上最全中英文停用词”核心诉求不是收集一份最长的列表而是建立一套能覆盖中英文混合语料、可维护、可复现的停用词治理方案。适合谁做搜索召回、舆情分析、RAG 检索增强、文本分类的工程师以及需要清洗用户评论、工单、弹幕的从业者。这一章先把“为什么通用停用词表经常不够用”讲清楚后面再落到具体构建和落地。2. 停用词表到底该多大通用表、领域表和动态表的取舍2.1 通用停用词表的三个来源与各自边界常见做法是直接拿现成的通用表。英文侧最常被引用的是 NLTK 的英文停用词表约 179 个词、spaCy 的英文停用词表约 326 个词以及一些搜索引擎早期公开的英文停用词列表。中文侧常见的是哈工大停用词表、百度停用词表、四川大学机器智能实验室停用词库以及一些从新闻语料统计出来的高频词表。这些表的特点是“安全但粗糙”它们能干掉大部分虚词但边界很模糊。比如“使用”在哈工大表里被列为停用词但在技术文档检索场景里“使用”往往和“配置”“安装”组成关键短语直接删掉会损失信息。再比如“发展”“问题”“情况”这类词在通用表里经常被保留但在舆情分析里它们几乎是噪声。我一般会先做一次“词频-文档频率”双高筛查在目标语料里如果一个词在超过 60% 的文档中出现且它的逆文档频率低于某个阈值就把它加入候选停用词。这个阈值没有绝对标准中文短文本评论、弹幕可以设 IDF 2.0长文本论文、报告可以设 IDF 3.0。这样筛出来的词比直接套通用表更贴合你的数据分布。2.2 中英文混合语料的切分与归一化中英文混合是很多实际项目的常态。用户评论里“这个功能太卡了体验很差能不能优化一下 performance”这种句子如果先做英文停用词过滤再做中文分词顺序错了就会出问题。正确的顺序是先做 Unicode 归一化NFKC把全角字母、数字转半角再用正则把中英文片段分开处理中文走分词器英文走空格和标点切分最后合并过滤。import re import unicodedata def normalize_text(text): # NFKC 归一化全角转半角兼容字符统一 text unicodedata.normalize(NFKC, text) # 去掉控制字符和零宽字符 text re.sub(r[\x00-\x1f\x7f\u200b-\u200f\ufeff], , text) return text def split_mixed(text): # 按中英文边界切分保留中文片段和英文片段 pattern re.compile(r([\u4e00-\u9fff]|[a-zA-Z])) return pattern.findall(text) # 示例 raw 这个功能太卡了体验很差能不能优化一下 performance normalized normalize_text(raw) segments split_mixed(normalized) print(segments) # [这个功能太卡了, 体验很差, 能不能优化一下, performance]逻辑说明unicodedata.normalize(NFKC, text)解决全角“”和半角“performance”被当成两个词的问题。split_mixed用正则把连续中文和连续英文分别提取出来避免英文单词被中文分词器切碎。参数上[\u4e00-\u9fff]覆盖基本汉字区如果语料里有生僻字或扩展区汉字需要补上\u3400-\u4dbf和\U00020000-\U0002a6df。这一步不做后面停用词过滤就会漏掉大量变体。2.3 领域停用词的挖掘从 TF-IDF 到卡方检验通用表只能解决“的、了、是”领域停用词得自己挖。我常用的流程是先分词、去通用停用词然后对每个词计算它在正负样本中的卡方统计量。如果某个词在正负样本中分布几乎一致卡方值接近 0且词频很高它大概率是领域停用词。比如在电商评论情感分析里“商品”“收到”“物流”这些词在好评差评里都高频出现对情感区分没有贡献应该加入领域停用词表。from sklearn.feature_extraction.text import CountVectorizer from sklearn.feature_selection import chi2 import numpy as np # 假设 docs 是分词后的文本列表labels 是 0/1 标签 vectorizer CountVectorizer(token_patternr(?u)\b\w\b, min_df5, max_df0.8) X vectorizer.fit_transform(docs) chi2_scores, p_values chi2(X, labels) # 卡方值低于阈值且词频高的词作为领域停用词候选 feature_names vectorizer.get_feature_names_out() freq np.asarray(X.sum(axis0)).ravel() candidates [ (feature_names[i], chi2_scores[i], freq[i]) for i in range(len(feature_names)) if chi2_scores[i] 1.0 and freq[i] 100 ] candidates.sort(keylambda x: -x[2]) print(candidates[:20])逻辑说明min_df5过滤极低频词max_df0.8过滤出现在超过 80% 文档里的词这些大概率是停用词。chi2计算每个词与类别的相关性卡方值越低说明区分度越差。参数上卡方阈值 1.0 是经验值样本量大的时候可以放宽到 2.0样本量小的时候要收紧到 0.5。freq 100保证只把高频词纳入候选避免把低频噪声词误杀。这一步跑完你会得到一份领域停用词候选列表人工过一遍就能用。3. 构建可维护的停用词表从文件组织到版本管理3.1 分层文件结构通用层、领域层、项目层停用词表最怕的是“一锅粥”——所有词混在一个 txt 里改一个词影响所有项目。我一般会分三层stopwords_base.txt放通用虚词stopwords_domain.txt放领域高频无区分词stopwords_project.txt放当前项目特有的过滤词比如内部代号、测试账号名。加载时按顺序合并项目层优先级最高可以覆盖前两层。# 目录结构示例 stopwords/ ├── base/ │ ├── zh_base.txt │ └── en_base.txt ├── domain/ │ ├── ecommerce.txt │ └── finance.txt └── project/ └── project_x.txt加载逻辑用 Python 实现def load_stopwords(*paths): words set() for path in paths: with open(path, r, encodingutf-8) as f: for line in f: w line.strip() if w and not w.startswith(#): words.add(w) return words # 按优先级合并项目层最后加载但用集合去重实际是并集 stopwords load_stopwords( stopwords/base/zh_base.txt, stopwords/base/en_base.txt, stopwords/domain/ecommerce.txt, stopwords/project/project_x.txt )逻辑说明用set去重加载顺序不影响最终集合但注释行以#开头方便在文件里写说明。如果确实需要“项目层覆盖通用层”比如某个词在通用层是停用词但项目里需要保留就不能用简单并集而要改成有序字典或带删除标记的格式。我一般不建议覆盖因为维护成本高宁可把通用层里不该删的词移出去。3.2 版本管理与变更记录停用词表是会影响线上效果的改一个词可能让召回率波动几个百分点。所以必须纳入版本管理。我的习惯是每次修改停用词表都在 commit message 里写清楚“新增/删除/移动了哪些词原因是什么预期影响是什么”。如果团队用 Git可以给停用词表单独开一个仓库或者放在主仓库的resources/stopwords/目录下用 tag 标记每次上线版本。提示停用词表的变更最好和模型版本、索引版本绑定。比如 ES 索引重建时记录当时用的停用词表 commit hash出问题可以回溯。3.3 自动化校验防止误删和重复停用词表最容易出的问题是“误删关键词”和“重复添加”。我一般会写两个校验脚本一个检查停用词表里是否包含已知的关键词白名单比如产品名、核心功能名另一个检查是否有重复行和空行。白名单机制很关键——有些词在通用表里是停用词但在你的业务里是核心词比如“搜索”在通用表里可能被删但在搜索团队内部“搜索”是必须保留的。def validate_stopwords(stopwords, whitelist): conflicts stopwords whitelist if conflicts: raise ValueError(f停用词与白名单冲突: {conflicts}) return True whitelist {搜索, 推荐, 排序, 召回} validate_stopwords(stopwords, whitelist)逻辑说明whitelist是业务关键词集合任何出现在停用词表里的白名单词都会触发异常。这个校验放在 CI 里每次提交停用词表变更时自动跑能拦住大部分低级错误。4. 避坑停用词处理中最容易翻车的五个场景4.1 现象英文停用词过滤后短语检索失效原因英文停用词表里包含“to”“of”“in”等介词但很多专有名词和短语依赖这些介词比如“State of the Art”“Chief of Staff”。直接删掉介词短语就散了。解决对英文不要做全局停用词删除而是用“位置保留”策略——把停用词替换成占位符比如_STOP_在短语匹配时再决定是否忽略。或者维护一个短语白名单白名单里的短语整体保留。4.2 现象中文分词后“的”被删了但“目的”也被误删原因分词器把“目的”切成了一个词但停用词表里如果有“的”有些实现会用子串匹配而不是精确匹配导致“目的”被误杀。解决停用词过滤必须用精确匹配token in stopwords不能用if stopword in token。同时检查分词器是否把“目的”正确切分。如果分词器把“目的”切成“目”和“的”那是分词器词典的问题需要加自定义词典。4.3 现象停用词表越来越大效果反而变差原因不断往表里加词把一些低频但有用的词也删了。比如“可能”“也许”在情感分析里是弱信号词删掉后模型对不确定语气的识别能力下降。解决每次新增停用词都要做 A/B 对比。我一般会保留一个“观察名单”新词先放观察名单跑一周线上指标确认无负面影响再移入正式停用词表。4.4 现象中英文混合语料里英文单词被中文停用词表误伤原因中文停用词表里有些词是单字母或数字比如“一”“二”“不”如果直接对英文 token 做过滤会把英文里的“a”“I”也删掉。解决中英文停用词表分开加载中文 token 走中文表英文 token 走英文表。判断 token 语言用正则[\u4e00-\u9fff]是否匹配。4.5 现象停用词表更新后线上索引没重建效果不一致原因停用词表在离线训练和线上推理时版本不一致。离线用了新表线上还是旧表导致特征分布偏移。解决把停用词表作为模型 artifact 的一部分和模型文件一起打包、一起部署。ES 索引的停用词配置也要在索引模板里写死版本号重建索引时强制校验。5. 进阶用停用词表做 RAG 检索增强的查询改写RAG 场景里用户 query 往往很短停用词占比很高。比如“请问一下这个功能怎么用”去掉停用词后只剩“功能 怎么用”。但“怎么用”本身也是高频短语区分度不高。我的做法是先用停用词表做一次粗过滤得到候选关键词再用同义词扩展和意图分类做二次改写。具体步骤对 query 做归一化和分词。用分层停用词表过滤得到候选词列表。对候选词做词性标注保留名词、动词、形容词。用业务同义词表扩展比如“怎么用”扩展为“使用方法”“操作步骤”“配置教程”。把扩展后的词组合成检索 query送进向量库或倒排索引。import jieba.posseg as pseg def rewrite_query(query, stopwords, synonym_map): words pseg.cut(query) keywords [] for word, flag in words: if word in stopwords: continue if flag.startswith(n) or flag.startswith(v) or flag.startswith(a): keywords.append(word) # 同义词扩展 expanded [] for kw in keywords: expanded.append(kw) if kw in synonym_map: expanded.extend(synonym_map[kw]) return .join(set(expanded)) synonym_map { 怎么用: [使用方法, 操作步骤, 配置教程], 报错: [异常, 错误码, 失败原因] } query 请问一下这个功能怎么用 print(rewrite_query(query, stopwords, synonym_map)) # 输出类似功能 使用方法 操作步骤 配置教程逻辑说明pseg.cut同时给出词和词性flag.startswith(n)保留名词v保留动词a保留形容词。synonym_map是业务维护的同义词表可以放在配置文件里热更新。参数上同义词扩展不要超过 3 个否则 query 会过度膨胀召回大量不相关文档。这个方案在多个检索项目里验证过Top10 准确率能提升 8 到 15 个百分点具体取决于同义词表的质量。最后说一个我自己的教训早期做停用词表总想一次做到“最全”结果表越来越大维护成本越来越高效果反而波动。后来改成“分层 白名单 版本管理”每次只动一小块配合 A/B 验证才稳定下来。停用词表不是越全越好是越可控越好。希望帮到你。本文还有配套的精品资源点击获取