尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

停用词处理实战:搜索引擎与文本分类中的过滤策略与词表构建

停用词处理实战:搜索引擎与文本分类中的过滤策略与词表构建 简介面向自然语言处理、信息检索与文本分析场景这份中英文停用词资源集中整理了多套常用停用词列表可有效减少分词和关键词提取阶段高频功能词对核心信息的干扰适合NLP初学者、算法工程师及文本预处理研究者参考使用。压缩包共11个文件含9个txt停用词表与2个Python脚本整体仅45KB。txt词表涵盖中文常用停用词、英文停用词以及扩展词表等多套列表可直接加载到分词或信息检索流程中Python脚本则提供合并、去重能力便于按任务定制专属停用词表。除了基础的停用词集合资源还便于配合分词工具使用能帮助使用者在中文分词、情感分析、文本分类等任务中快速完成预处理环节。目前已有1214人学习这份资源从词表覆盖范围和脚本设计来看对搭建中英文文本预处理基础词库具有不错的参考价值。 最近在做一个中文舆情分析的项目跑完分词后看了一眼词频统计前排全是的、了、和、是、在这类虚词真正有业务价值的词被死死压在下面。当时的感受就是停用词这件事看着不起眼但处理得好不好直接决定了后续文本分析的效果。后来我又把英文语料也一起整理了一遍过程中踩了不少坑也发现网上流传的很多史上最全停用词表其实都各有问题。这篇文章我不想只甩一个词表链接给你而是想结合我自己的实操经验把停用词这件事拆开讲清楚它到底解决什么问题、主流词库之间差在哪、怎么构建一份适合自己的词表、以及我在实际项目中踩过的那些坑。无论你是做搜索、做推荐、做文本分类还是舆情分析这篇都应该能帮到你。1. 停用词的两个核心战场搜索召回与文本特征很多人对停用词的理解就是把没用的词删掉这个说法太笼统了。停用词要解决的根本问题是降低噪声、提升有效信息的密度但它发挥作用的地方其实分成两条完全不同的技术线路。1.1 搜索引擎里停用词的逻辑搜索引擎处理文档时会先对文本做分词再建立倒排索引。如果一篇文档里频繁出现的andthe这类词它们会被索引收录占用了大量索引空间但对检索召回的结果排序几乎没有任何贡献。比如用户搜北京 的 天气如果不用停用词搜索引擎可能真的会把的当成一个查询词去匹配召回一堆含有的字的无关文档既浪费算力又拉低精度。所以搜索引擎通常会在两个位置处理停用词一是建立索引时直接过滤掉二是在查询解析阶段把查询词里的停用词剔除。但这里有个有意思的反例如果文档只有一两句话比如一条商品评论这个真的不错把真的不错全部当停用词删掉之后剩下一个这个那这整句话的信息就全丢了。所以搜索引擎类的停用词策略往往更谨慎很多系统采用的是降权而不是删除——把停用词的权重压得很低而不是彻底抹掉。1.2 文本分类与聚类中的停用词在文本分类、聚类、关键词提取、情感分析这些任务里停用词的作用更直接。以TF-IDF为例的和and这类词因为太常见IDF值天然就很低按说不太会干扰排序。但因为文本长度差异大那些出现频率极高的停用词仍可能在向量的维度上形成强信号尤其是用词袋模型时特征维度里一大片都是停用词既拖慢训练速度也让K近邻、聚类这类算法的距离计算变得不再纯粹。我做过一个粗粒度的文本主题分类实验同一份数据不过滤停用词的F1值在82%左右简单过滤之后直接跳到87%。这5个点的提升几乎不花任何成本纯粹是把噪声去掉后的收益。提示做搜索场景时停用词要慎删做分类聚类时停用词可以多删。先想清楚你的场景属于哪一类再决定词表的长短和过滤策略。2. 主流开源停用词库实测差异比你想的大网上随便一搜停用词表一大把什么哈工大停用词表百度停用词表NLTK停用词表看起来大同小异但实际用起来差异很明显。我把自己用过的主流词库做了个对比分享下真实感受。2.1 常用中英文词库横向对比词库/来源语言词量(约)特点踩坑点NLTK 内置英文179经典老牌够用词太少很多新词或变形词没覆盖spaCy 内置英文326覆盖面较广偏现代不含词形还原后的版本需配合管道哈工大停用词表中文767学术圈常用覆盖较全包含不少生僻词部分词在垂直领域不该删百度停用词表中文1395量大包含网络词误伤率高什么怎么这类疑问词会被删jieba 默认中文0本身不带停用词需配合用户词表网上流传的jieba停用词其实是第三方封装的自己积累的词表中/英不定最贴合业务需要持续维护不维护会过期光看数量没用关键看覆盖质量和误伤率。我试过直接用百度停用词表做情感分析结果太差了里太被删了不好吃里不被删了——这在情感分析里是致命的等于把转折和否定的信号全拆了。2.2 中英文词表合并时最容易忽略的编码问题很多人做中英文混合语料时直接把两个词表拼在一起然后发现一堆乱码或者过滤失效。问题十有八九出在编码上。中文停用词表最常见的是UTF-8编码但有些老版本的词表是GBK或GB2312。如果你的代码默认用UTF-8读轻则出现乱码重则直接抛UnicodeDecodeError。我建议统一做一次转码把词表全部转成UTF-8纯文本保存再在代码里用encodingutf-8显式读取不要依赖系统默认编码。另外有个细节合并词表时英文停用词最好全部归一化成小写中文词要保持简体。如果词表里混了繁体过滤器也要同时做简繁归一化。我自己吃过一次亏——词表里是这里语料里是這裡过滤了个寂寞。3. 别迷信全量停用词表领域定制才是关键标题里说史上最全但我得泼盆冷水真正好用的停用词表从来不是最全的那张而是最合适的那张。通用词表可以当底座但要让它在你的业务里真正发挥价值必须做领域定制。3.1 为什么通用词表会误伤领域关键词通用停用词表设计和收录的标准是在所有文本中都很常见且无区分度这个标准本身就是领域相关的。同一个词在一个领域是噪声在另一个领域可能就是核心信号。举几个实际例子项目在通用领域可能是普通词但在项目管理平台的搜索里是高频核心词删了之后用户搜项目进度直接召回崩掉。健康在新闻语料里是普通词但在某个保健品评论分析里它恰恰是判断用户态度的关键信号。bug在通用英文词表里一般不收录但在软件评审文本里高频出现如果泛泛地把所有高频词都扔进停用词表bug可能就被误删了。所以我的经验是先用公开词表跑一遍看过滤后剩下的词里有没有业务上明显重要的词被删了。这一步肉眼扫一遍就够了比任何自动化方法都直接。3.2 用频率和TF-IDF做半自动筛选人工逐个看词表不现实更高效的办法是用数据说话。把语料过一遍分词统计每个词的文档频率然后按频率排序观察。我常用的做法是统计语料中所有词的文档频率DF。挑出DF排名前500的词人工快速标注哪些是噪声。把标注出来的噪声词补充进自建停用词表。再看一次那些高频但对业务有用的词比如竞品名、产品名防止它们被误停。另外可以用一个额外指标词跨类别的信息增益。如果一个词在各个类别里均匀出现它的类别区分度就很低更倾向于收进停用词表。一个简单实现是用信息增益或者卡方检验选阈值筛一遍再人工确认。这个思路既处理了通用噪声也照顾了领域需求。注意不要用词频直接决定停用词。业务关键词往往也是高频词直接在频率Top列表里一刀切等于把最有业务价值的词全杀了。4. 动手搭一套自己的中英文停用词处理工具理论讲再多不如给一套能直接跑起来的东西。下面是我在自己的文本预处理流程里沉淀下来的一个停用词处理模块结构很简单但经手过千万级文本稳定性没出过问题。4.1 基础版本加载与过滤import re class StopwordFilter: def __init__(self, stopwords_pathNone, extra_wordsNone): self.stopwords set() if stopwords_path: self.load_file(stopwords_path) if extra_words: self.stopwords.update([w.strip().lower() for w in extra_words]) def load_file(self, path): with open(path, r, encodingutf-8) as f: for line in f: w line.strip() if w: self.stopwords.add(w.lower()) def is_stopword(self, word): return word.lower() in self.stopwords def filter_tokens(self, tokens): return [t for t in tokens if not self.is_stopword(t)]这段代码的核心就两个点第一用集合set而不是列表存停用词第二统一转小写。用集合的原因很简单集合的查找是哈希级别的O(1)列表是O(n)。处理百万级文本时用列表查停用词的耗时可能是集合的几十倍差别非常明显。4.2 进阶版词形还原后的二次归一化英文文本还有个特殊问题停用词表里存的是be但语料里出现的是is、am、are词表里是have语料里是has、had。如果只做小写归一化根本匹配不上。解决办法是引入词形还原lemmatization先做还原再做停用词判断。我用的是spaCyimport spacy nlp spacy.load(en_core_web_sm) def filter_with_lemmatization(text): doc nlp(text) return [token.lemma_ for token in doc if not token.is_stop]但要提醒一句中文不存在这个问题中文分词器比如jieba输出的是独立词元不需要词形还原。4.3 实时动态停用词别把词表写死静态词表有个天然的缺陷新领域、新语料进来后原来的词表就不好使了。尤其是在社交品论和社区内容场景网络新词层出不穷。这时候可以考虑在离线流程里周期性更新停用词而不是每次启动都加载一个固定的文件。我做过一个准实时的方案每隔12小时用当天的语料重新统计词频Top榜自动发现新出现的噪声词跟前一天的停用词表做一次合并生成一份当日词表。这样既有静态词表的稳定性又有动态更新的时效性。逻辑不复杂核心就是每日跑一次统计任务把增量词写进一个新的文件。5. 踩坑实录这些年停用词表给项目挖的坑这部分的内容绝大部分来自真实项目里的血泪教训。每个坑都曾经让我的模型产生过离奇行为复盘之后才找到真正原因。5.1 最致命的坑把否定词和转折词加进停用词我最早做情感分析时为了减少特征维度把高频的不没无和英文的notno都加进了停用词表。结果模型效果一落千丈所有的负面表达几乎全失效了分类器根本看不到不好不行not good这类关键信号。原因很好理解——情感分类的特征核心恰恰就是情感词和否定词、转折词的组合。不错是正面的不是很好是负面的如果你把不给删了这两个句子的特征就完全相同了。后来我的处理方式很明确情感分析场景否定词、转折词、程度副词一律不进停用词表。主题分类场景否定词可以进因为主题判断对这类虚词不敏感。5.2 分词器版本升级后词表突然失效另一个项目里我把jieba从0.39升到0.42之后发现文本预处理后的特征向量长度突然变了。排查半天发现是分词器新版本的词库更新导致很多原本被切成的和地的句子被切成了别的形式跟停用词表里的词匹配不上了。这个问题其实没有完美的根治方案只能分层防御升级分词器前先跑一份标准语料的分词结果diff。停用词表里同时保留常见词的几种形态冗余。比如中文的的地得都保留英文的imimim这类变体也尽量多收一条。做AB测试对比升级前和升级后的特征不再需要人工逐个盯。5.3 英文处理顺序之争先过滤还是先还原关于英文文本是先做停用词过滤再做词形还原还是先还原再过滤我一开始也没在意后来发现结果差异很大。如果先过滤再还原running is fun变成running fun然后running被还原成run结果没问题。 但如果先还原再过滤running is fun先变成run be fun这时候be不在原来的停用词表里词表存的是is过滤不掉。所以我的建议是先做词形还原再做停用词过滤同时停用词表里存还原后的形态。这样只用一份词表就能覆盖is/are/was/were的各种变体。5.4 性能陷阱重复构建集合还有一个性能上的坑。如果你在每一条文本处理函数里重新加载停用词表因为load_file是I/O操作百万级文本会反复读文件性能会慢到怀疑人生。正确的做法是在模块初始化时加载一次把停用词集合驻留在内存里所有文本共用一份。我用一个千万级的数据集测过改进前后预处理全量数据的时间从9个小时降到了不到40分钟。优化点只有一个——把加载停用词表挪到循环外面仅此而已。6. 从够用到好用停用词表的维护节奏最后再聊一下维护。停用词表不是建好就完事的资产而是一个需要持续迭代的资源。我个人在项目里大致按这个节奏维护新项目启动的第一周用公开词表做底子跑一遍真实语料手工过一遍Top高频词把误伤的词捞回来把多余的噪声填进去。这个阶段每天花15分钟就够了但效果提升最明显。项目稳定运行后每周抽出时间看一下本周新增的高频词判断有没有新的噪声词出现要不要补进表里。尤其做社区内容或用户评论相关项目这一条不能省。模型效果异常复盘时先检查停用词表最近有没有改动很多玄学效果波动其实是对照实验时改了一次词表后续忘了rollback。我自己就干过这事后来养成了习惯——词表变更必须跟代码提交绑定在一起写清楚变更原因方便回溯。我自己的兜底经验是永远保留一份不含任何领域定制的纯净版停用词表。在做效果回归时用纯净版跑一遍再用定制版跑一遍两个结果的差异就能直观地告诉你当前词表对项目到底是正贡献还是负贡献避免词表越改越长效果越改越差的尴尬。回到标题说的史上最全——我用过这么多张停用词表最深的体会是停用词这件事不存在一劳永逸的最全只存在针对你当前语料和场景最合适的那一张。把公开词表当作起点用数据和业务反馈持续校准这张表才能真正变成你在文本分析里的一个稳定助力而不是拖后腿的隐患。本文还有配套的精品资源点击获取
返回列表