想象你是邮局新来的分拣员小邮,第一天报到就面临难题:办公桌上堆着一千多封来信,其中不少是“免费中奖”“限时折扣”这类垃圾广告,甚至还有几封写着“恭喜您获得500万奖金”的诈骗信。师傅老王把一叠信往桌上一摊,说:“从今天起,你的任务就是从正常信件里把垃圾信挑出来。别小看这活儿——邮件一多,光靠肉眼就会看漏。”小邮挠挠头,心想这跟计算机有什么关系?老王笑了:“机器也一样,但机器可以用一套方法,把'看信'变成数学计算。今天我就带你走一遍完整的流程。” 这就是机器学习里经典的文本分类任务——垃圾邮件过滤。这篇实战文章会陪你走完整个流程:整理原始邮件数据、把文字变成数字特征、训练朴素贝叶斯分类器、调整拦截阈值、用指标评估效果,最后讨论如何落地部署。我们不从抽象理论出发,而是一步步亲手搭建一个可运行的过滤系统。学完它,你就掌握了邮件网关、内容审核这类二分类文本过滤业务的完整套路。
学会垃圾邮件过滤全流程,你就能独立搭建邮件网关、内容审核等二分类过滤系统,这是算法工程师面试和落地必备的核心实战技能。
可视化演示
展示朴素贝叶斯垃圾邮件过滤核心原理:后验概率计算、六阶段过滤流水线、精确率召回率评估。切换模式探索不同环节。
本节配有交互动效(进入视口后自动加载,约 3KB)。
贝叶斯后验概率计算 利用贝叶斯定理,根据词语在垃圾/正常邮件中的出现频率计算后验概率P(垃圾|词语) 朴素假设:词语间相互独立,联合概率为各词概率乘积 P(S|W) = P(W|S)·P(S) / P(W) 后验概率超过阈值则判定为垃圾邮件
案例背景与目标
小邮第一天到邮局报到,办公桌上堆着刚到的信件:有手写的家书、打印的账单、花花绿绿的广告传单,还有几封写着“恭喜您中奖”的诈骗信。师傅老王把这些信翻来覆去地展示给他看:“你得先明白自己要拦什么、为什么拦。广告是垃圾信,诈骗更是垃圾信;朋友寄来的明信片是正常信,银行账单也算正常信。目标清楚了,才好做技术方案。”
这其实是一个标准的机器学习二分类任务。我们给每封邮件打一个标签:1 表示垃圾(spam),0 表示正常(normal)。机器要学的,就是从历史邮件中找出规律,然后对新来的邮件做出判断。听起来抽象,但目标很具体:垃圾识别率尽量高、正常邮件别被误伤、同时速度要足够快,以应对每日海量新邮件。在工业界,这个任务落地在邮件网关、社交平台评论审核、短信反诈骗等场景,是每个算法工程师都要掌握的基本功。
工程上,这个任务可以拆成四个阶段:先准备带有标注的数据集并做预处理,再把文本转成特征向量,接着训练一个分类器,最后在测试集上评估效果并调整阈值。后面的章节会依次展开,每一步都对应我们刚才说的“看信”行为:整理信纸、划重点、翻经验簿、调火候、看成绩单。
小邮在本子上写下自己的三句话目标:眼要准(高召回)、手要稳(低误杀)、动作要快(高性能)。他心里清楚,这跟机器学习工程师做项目的目标是一致的——先定义清楚问题,再去选择工具,永远不要让方法先于问题。
数据集预处理
老王有一套“拆信十八手”:先撕掉信封看正文;把英文大写全部转成小写;把拼错的单词记下来修正;最后把“的、了、吗”这类没信息量的词划掉。小邮不解:“为什么费这么大劲?”老王笑了:“信纸整理干净了,上面的字才看得清。如果你把带着泥土和褶皱的信纸直接交给机器,机器只会更糊涂。”
原始邮件文本往往是脏乱的:包含 HTML 标签、URL、大小写不一、标点混乱,还有大量停用词。如果直接把原始字符串喂给算法,同一个词会因大小写不同被当成两个特征,“GET“ 和 ”get” 统计不到一起,HTML 标签也会被当成有意义的词。预处理的目标就是把噪声去掉,让文本变成干净的 token(词元)序列,通常被称为分词与清洗管线。
标准流程是:采集邮件并标注 → 抽取正文 → 去 HTML 标签 → 统一转小写 → 分词 → 去停用词 → 得到词列表。例如 “Free IPHONE case!!!“ 会变成 ['free', 'iphone', 'case']。停用词表通常包括 the、a、is、are 等高频无意义词,它们在垃圾和正常邮件里都会出现,对分类没有区分度。注意:预处理不是越狠越好。对朴素贝叶斯来说,过度清洗(比如去掉所有标点符号甚至数字)反而可能丢掉”限时5折”这类有用的数字信号,所以一般只做基础清洗。
经过这套“拆信十八手”,小邮手上的信纸变得干净、整齐、格式统一,读起来一目了然——数据预处理的价值也正在于此:它决定了后续所有特征和模型能看到的“信息质量”。垃圾进,垃圾出,这条铁律在机器学习里永远适用。
特征提取方法
老王让小邮在干净的信纸上划重点:“看到免费、中奖、现金、紧急这些词,就画一个红圈。哪个词在信里出现得越多,圈就越多,这封信的可疑程度就越高。”小邮问:“要是整封信都在说会议、报告呢?”老王点点头:“那你就放心放行。关键词就是证据。”
计算机不认识“免费”这类单词,只认识数字。特征提取就是把文本变成特征向量的过程。最基础的方法是词袋模型:维护一个词汇表,统计每个词在邮件中出现的次数。这样每封邮件就变成一个向量,比如某个词的词频是 3,另一个词是 0,向量形如 (3, 0, 1, ...)。词频(Term Frequency,TF)反映了词在文档里的热度,但有个问题——“邮件”“主题”这类词在垃圾和正常邮件里都常见,区分度有限,反而可能干扰判断。
于是人们引入 TF-IDF(词频-逆文档频率)来给特征加权:
划完重点的小邮发现,“免费”被画了五个圈,“会议”只出现两次,他心里对这封信的去向已经有了初步判断。特征提取的本质就是这样——从一句话里找出“可疑的碎片”,把人类阅读时的直觉,变成机器可以计算的一串数字。
- 词频项 $tf(t, d)$先看单个词在当前文档里的出现次数。出现越多,说明它越可能是这封邮件的“主题词”,这是基础热度指标。
- 逆文档频率 $idf(t)$
log起压缩尺度的作用,N是训练集总文档数,df(t)是包含词t的文档数。几乎所有邮件都出现的“的”"the",其idf趋近于 0,自动降权。 - 综合加权把词频和逆文档频率相乘,常见词被压低,罕见但关键的词(如“中奖”)被放大,得到更有区分度的特征权重。
朴素贝叶斯训练
老王泡好茶,从抽屉里取出一本厚厚的经验簿:“我分拣了三十年信,这里记着每个词在垃圾信和正常信里出现的次数。比如'免费'在 1000 封垃圾信里出现 300 次,在 1000 封正常信里只出现 5 次。你翻着簿子做推断,就是贝叶斯方法的思路。”小邮眼前一亮:“原来经验可以这样量化!”
朴素贝叶斯要回答的问题正是:给定一封邮件的所有词,它是垃圾的概率有多大?我们用贝叶斯公式把这个问题拆解成几个可以统计的部分:
训练的本质就是统计经验簿上的数字:先算好先验概率,再统计每个词在各类邮件中的出现比例。但这里有一个致命陷阱:如果某封正常邮件里从没出现过“中奖”这个词,它的概率就是 0,连乘后整封邮件的概率直接变成 0,模型会武断地认为这不可能。解决办法是拉普拉斯平滑:
小邮的经验簿越记越厚:不仅知道“免费”长什么样,还能算出它出现在垃圾信里的具体概率。他学会的正是朴素贝叶斯——简单、快速、可解释,是落地最快的文本分类方法之一,也难怪邮箱服务商从二十年前就开始用它过滤垃圾邮件。
- 分子加 1给没出现过的词也保留一个最小概率,避免零概率把整个乘积清零。
- 分母加 $V$$V$ 是词汇表大小(训练集中所有不同词的个数),加 $V$ 是为了让所有词的概率之和仍然等于 1,不破坏概率分布的合法性。
- 效果平滑后,高频词的估计值略微下降,罕见词获得一个很小的非零概率,模型对新词的容忍度大幅提升。
阈值调优策略
上岗几天后,小邮发现一个头疼的问题:有些信介于可疑和正常之间。他问老王:“这种灰色信件到底拦不拦?”老王指着分拣桌上的旋钮说:“这本就是一个选择题。旋钮拧紧一点,垃圾信进不来,但也有可能把朋友的明信片当成广告扔掉;拧松一点,少冤枉好人,可骗子信就会混进来。”小邮有些紧张:“那到底拧到哪?”
在数学上,这个旋钮就是阈值 $\theta$。朴素贝叶斯输出的垃圾概率是一个 0 到 1 的分数,我们需要一条决策线:分数大于等于 $\theta$ 就拦截,否则放行。很多人以为 0.5 是默认答案,其实 0.5 只是数学上的对称中点,业务上往往不是最优解:
调整 $\theta$ 会直接改变两种错误的相对比例:误杀率(正常邮件被当垃圾,即 FP 率)和漏杀率(垃圾邮件被放行,即 FN 率)。两者此消彼长:$\theta$ 调高,拦截变少,漏杀增多、误杀减少;$\theta$ 调低,拦截变多,误杀增多、漏杀减少。业务场景决定取舍——对安全要求高的钓鱼邮件防护,宁可误杀几封正常订阅邮件,也不能放过一条钓鱼链接;对用户体验敏感的营销邮箱,宁可漏放几封广告,也不能把客户的重要邮件扔进垃圾箱。
调参方法常用网格搜索:在验证集上遍历 0.1 到 0.9 的阈值,计算每个点对应的业务损失,选损失最小的位置。小邮慢慢理解了,没有绝对正确的旋钮位置,只有适合当前业务的旋钮位置。调阈值就像调火候,火大糊了,火小生了,总得试过才知道。
- 后验概率 $P(\text{spam}|\text{mail})$这是模型输出的核心分数,反映一封邮件是垃圾的可能性,范围在 0 到 1。
- 阈值 $\theta$一个可调节的决策临界点。调大意味着更保守,只有非常有把握才拦截;调小意味着更激进,稍有嫌疑就拦截。
- 预测标签 $\hat{y}$把连续分数变成离散的 0/1 判断,1 表示放入垃圾箱,0 表示放入收件箱。
效果评估指标
周末,老王给小邮做了一次结业考核。他把一周的分拣结果摊开,让小邮记录四笔账:拦对的(确实是垃圾)、拦错的(正常信被扔)、漏掉的(垃圾信混进去)、放行的(正常信通过)。小邮很快记好了:总共 50 封垃圾信拦住了 45 封,放走了 5 封;100 封正常信里有 8 封被误扔。老王让他算算自己干得怎么样。
这四笔账在机器学习里就是混淆矩阵的四个格子,分别叫 TP(真正例)、FP(假正例)、FN(假负例)、TN(真负例)。由它们可以计算出一系列评估指标:
初学者最容易瞄一眼准确率就下结论,但在垃圾邮件场景中,垃圾邮件往往只占很小比例。假设垃圾只占 2%,模型把所有邮件都判为正常,准确率依然高达 98%,看起来“很棒”,可实际上垃圾邮件一封都没拦住。这就是为什么我们要看混淆矩阵和精确率、召回率——它们专门捕捉“少数但关键的类别”的表现。
拿着这四笔账,小邮清楚地看到自己的短板:想提高召回率,他就把旋钮往低调一点,多拦一些可疑信;发现误杀太严重,他又把旋钮往回收一收。数据不会说谎,指标就是成长的一面镜子。
- 混淆矩阵四格TP 是垃圾邮件被正确拦截,FP 是正常邮件被误拦,FN 是垃圾邮件漏网,TN 是正常邮件被正确放行,四者之和等于样本总数。
- 精确率 $P$(Precision)在所有被拦截的邮件中,真正是垃圾的比例,回答“拦得准不准”。
- 召回率 $R$(Recall)在所有垃圾邮件中,被我们拦住的比例,回答“漏得多不多”。
- F1 分数精确率和召回率的调和平均。当两者差距过大时 F1 会显著下降,所以它能有效阻止我们只优化其中一个指标。
落地部署考量
三个月后,小邮出师,独立负责一个邮政分拣口。老王临走时叮嘱了三件事:“第一,机器不能停,高峰期信件源源不断;第二,新的广告形式层出不穷,经验簿要常更新;第三,如果用户投诉说'我朋友的信被扔了',一定要认真听。”小邮把这些话一字不落地记在了心里。
工程落地的垃圾邮件系统也完全同理。训练好的模型不是放在实验室里“封神”的,而是要部署成在线服务,在邮件到达用户收件箱之前实时打分。同时,垃圾邮件是一场猫鼠游戏——广告模板每天都在变,昨天的特征今天可能就失效了,模型必须持续更新才能跟上节奏。
常见的落地形态有三点。第一是实时过滤管线:邮件到达 → 预处理 → 特征提取 → 模型打分 → 按阈值分流到收件箱或垃圾箱,整条链路延迟要求在毫秒级。第二是定期重训:每天或每周用新增的人工标注数据重新训练模型,或者在线增量更新参数,保证模型不过时。第三是用户反馈闭环:用户点击“标记为垃圾”或“这不是垃圾邮件”,这些反馈回流到训练集,成为下一轮迭代的原料。此外还要做监控报警——如果某天拦截率骤升,可能是阈值漂移、特征分布变化或数据采集异常。
小邮站在分拣口,手里攥着老王传下来的经验簿和数据,知道自己已经不是一个人在战斗了。模型、数据、反馈,共同构成了一套不断进化的过滤系统。这就是工程落地的真谛:不是训练完就结束,而是让系统在真实环境中持续奔跑、持续学习。
AI 应用场景
企业邮件网关过滤
阶段:部署与维护阶段
解决的问题:企业邮箱每天收到大量广告、钓鱼和诈骗邮件。传统规则库(黑名单、正则表达式)只能拦截已知模式,对变种广告和社工钓鱼束手无策。用朴素贝叶斯模型自动学习文本特征,可以在新邮件到达用户收件箱前实时打分拦截。
具体案例:某企业邮箱每天处理 10 万封入站邮件,接入基于文本特征的朴素贝叶斯分类模型后,92% 的垃圾邮件被拦截在网关层,用户关于垃圾邮件的投诉明显下降;模型每周使用用户标注数据重训一次,并通过监控报表跟踪拦截率和误杀率的变化。
社交平台评论审核
阶段:特征提取与模型推理阶段
解决的问题:评论区刷屏广告、导流垃圾信息如果靠人工审核,24 小时都盯不过来。把评论审核建模为“垃圾评论 vs 正常评论”的二分类问题后,可以在用户发布内容的同时完成毫秒级实时判断。
具体案例:某内容社区使用词袋特征 + 朴素贝叶斯模型,在 CPU 上达到单条评论 5 毫秒的推理延迟,每天处理百万级评论,将 80% 的广告评论自动折叠隐藏,显著降低了社区运营人力成本。
运营商短信反诈骗
阶段:数据采集与效果评估阶段
解决的问题:电信诈骗短信危害巨大,运营商需要识别“您获得 500 万奖金”之类的诈骗短信。将用户举报短信作为标注数据训练模型,再结合阈值调优在“多拦诈骗”和“少误伤正常短信”之间寻找平衡。
具体案例:某省级运营商基于用户举报加人工标注构建了 20 万条短信数据集,贝叶斯模型上线后诈骗短信识别召回率达到 87%,误杀率控制在 0.5% 以内,并配合阈值调整应对节假日诈骗短信高峰。
Python 演示
import mathimport refrom collections import Counter class SpamFilter: def __init__(self): self.word_counts_spam = Counter() self.word_counts_normal = Counter() self.total_spam_words = 0 self.total_normal_words = 0 self.spam_docs = 0 self.normal_docs = 0 self.vocab = set() self.threshold = 0.6 self.vocab_size = 0 def _tokenize(self, text): tokens = re.findall(r'[a-z0-9]+', text.lower()) stopwords = {'the', 'a', 'an', 'of', 'to', 'and', 'or', 'for', 'in', 'on', 'your', 'you', 'this', 'that', 'with'} return [t for t in tokens if t not in stopwords] def fit(self, texts, labels): for text, label in zip(texts, labels): tokens = self._tokenize(text) if label == 1: self.spam_docs += 1 self.total_spam_words += len(tokens) self.word_counts_spam.update(tokens) else: self.normal_docs += 1 self.total_normal_words += len(tokens) self.word_counts_normal.update(tokens) self.vocab.update(tokens) self.vocab_size = len(self.vocab) def _word_prob(self, word, spam): count = self.word_counts_spam[word] if spam else self.word_counts_normal[word] total = self.total_spam_words if spam else self.total_normal_words return math.log((count + 1.0) / (total + self.vocab_size)) def predict_score(self, text): tokens = self._tokenize(text) p_spam = math.log(self.spam_docs / (self.spam_docs + self.normal_docs)) p_normal = math.log(self.normal_docs / (self.spam_docs + self.normal_docs)) for word in tokens: if word in self.vocab: p_spam += self._word_prob(word, True) p_normal += self._word_prob(word, False) return 1 / (1 + math.exp(p_normal - p_spam)) def predict(self, text): return 1 if self.predict_score(text) >= self.threshold else 0 if __name__ == "__main__": emails = [ "Free iPhone case, click the link to get it now", "Meeting at 3pm tomorrow, please bring your laptop", "Congratulations! You won 5 million dollars, call us now", "The report is on my desk, pick it up later", "Limited offer! 50 percent off all products today", "Mom will pick you up at the airport this morning" ] labels = [1, 0, 1, 0, 1, 0] model = SpamFilter() model.fit(emails, labels) tests = [ "Congratulations, you won a free iPhone, click here", "Remember to submit your report by Friday" ] for t in tests: score = model.predict_score(t) print("text: %s score=%.2f predict=%d" % (t, score, model.predict(t)))
tokens = re.findall(r'[a-z0-9]+', text.lower())把英文文本统一转小写后切分成单词列表,一次完成转小写和分词两步。self.word_counts_spam.update(tokens)用 Counter 累加每个词在垃圾邮件中的出现次数,相当于在经验簿里记账。self.vocab.update(tokens)把新词收进全局词汇表;词汇表大小就是平滑公式里的 V。return math.log((count + 1.0) / (total + self.vocab_size))计算拉普拉斯平滑后的条件概率并取对数,防止连乘时数值下溢。p_spam = math.log(self.spam_docs / (self.spam_docs + self.normal_docs))统计先验概率并取对数,这是贝叶斯公式里的 P(spam)。return 1 / (1 + math.exp(p_normal - p_spam))用 sigmoid 把两类的对数得分差映射成 0 到 1 的垃圾概率分数。return 1 if self.predict_score(text) >= self.threshold else 0阈值决策:垃圾分数超过 threshold 就拦截,对应正文里的阈值调优。
常见误区
误区“朴素贝叶斯这个名字听起来就很低级,是不是因为我们没时间做复杂模型才用它?”
正解这里的“朴素”指的是朴素假设——假设各个词在给定类别下互不影响、相互独立。现实中“免费”和“中奖”经常一起出现,并不独立,但这个假设让计算量骤降且效果依然可观。它是一种用极简假设换取高效可用的经典设计,不是能力弱的表现。在老王的经验簿里,哪怕假设每个词单独记账,加起来判断垃圾信也已经非常准。
为何常见:中文“朴素”容易被理解成“简单粗糙”,实际上它指的是工程上主动选择的独立性简化,而不是模型本身很费。
误区“误杀率升高,意思是垃圾邮件漏网变多了。”
正解正好相反。误杀率是正常邮件被错误拦截的比例,对应 FP,意思是把好信扔了;漏杀率是垃圾邮件被放过的比例,对应 FN,意思是把垃圾信放进来了。两者都会随阈值变化,但方向相反:阈值调高,误杀降低、漏杀升高;阈值调低则反过来。理解这个小旋钮的两种效果,是调优的第一步。
为何常见:两个词都带“杀”字,初学者容易混淆宾语——误杀杀的是“无辜者”,漏杀漏的是“该杀的人”。
误区“我的模型在测试集上准确率 98%,说明系统特别可靠,不用再改了。”
正解在类别不平衡的场景下,准确率是“安慰性指标”。如果垃圾邮件只占 2%,模型把全部邮件判为正常,准确率也有 98%,可实际上垃圾一封没拦。正确的做法是看混淆矩阵,重点关注精确率和召回率——垃圾邮件过滤的目标不是“多数类都猜对”,而是“少数但关键的垃圾类尽量被识别”。
为何常见:准确率是大众最熟悉的指标,直觉上很“硬”,但它在不平衡二分类里极具欺骗性。
误区“拉普拉斯平滑给没出现的词硬加了概率,扭曲了真实统计,我把它去掉算了。”
正解平滑确实让估计值有轻微偏差,但这是“有偏但可靠”的代价。没有平滑时,一个从未见过的新词会把整个连乘直接清零,模型瞬间失明。平滑的本质是给零概率一个软着陆,用一点点精确度换取极大的鲁棒性。真实系统里,训练集永远覆盖不了所有可能的词,平滑是必需品而不是可选项。
为何常见:小样本下“没出现=概率0”的直觉很强,但统计中零概率往往来自样本不足,而非现实中真的不可能。
误区“模型输出概率大于等于 0.5 就拦截,这是行业标准,不能乱改。”
正解0.5 只是默认值,不是标准答案。业务优先级不同,阈值就该不同:宁可错杀也不放过钓鱼链接时用低阈值;对待敏感的商业订阅邮件,宁可漏掉几封垃圾也不误伤时用高阈值。阈值是调节“两种错误代价”的旋钮,必须根据具体场景用验证集去试。
为何常见:0.5 是概率空间里数学上的对称中点,教科书常拿它当默认值,让人误以为它对所有场景都最优。
面试题
Q1. 朴素贝叶斯中“朴素”一词指的是什么?
- A.代码实现起来非常简单
- B.假设特征在类别下条件独立← 正确答案
- C.只能处理文本分类任务
- D.训练过程不需要数据标注
答案:B。“朴素”特指条件独立假设——认为各词在类别给定后互不影响。选项 A 是字面误导;C 错,因为它也能处理离散和连续特征;D 错,分类任务必须有标注。正如老王的经验簿按词单独记账,正是“朴素”的体现。
Q2. 将分类阈值调高后,最直接的影响是什么?
- A.漏杀率降低但误杀率升高
- B.误杀率降低但漏杀率升高← 正确答案
- C.精确率与召回率同步上升
- D.模型准确率一定随之上升
答案:B。阈值调高意味着更保守,拦截的门槛更高,正常邮件被误拦减少(误杀率降),但垃圾邮件漏放增加(漏杀率升)。A 把两个方向写反了;C 不成立,两者通常此消彼长;D 不一定,准确率可能变也可能不变。
Q3. 拉普拉斯平滑在朴素贝叶斯中有哪些作用?
- A.避免未出现词导致零概率← 正确答案
- B.显著加快模型训练速度
- C.提升模型对词典外词的稳健性← 正确答案
- D.让特征词一定获得高权重
答案:AC。A 和 C 正确:平滑给未知词一个非零概率,避免连乘清零,提升稳健性。B 错,平滑不改变训练复杂度;D 错,平滑只是给小概率设下限,不会提高权重。就像经验簿里给没见过的词记一个最小账目,不影响其他词的排名。
Q4. 在混淆矩阵中,FN(假负例)表示什么分类结果?
- A.垃圾邮件被正确拦截
- B.垃圾邮件被错误放行← 正确答案
- C.正常邮件被误拦误杀
- D.正常邮件被正确放行
答案:B。FN 表示真实是正例(垃圾),但模型预测为负例(正常),即垃圾邮件漏网。A 是 TP,C 是 FP,D 是 TN。老王考核时最担心的就是这种“垃圾信混进了收件箱”的情况。
Q5. 垃圾邮件仅占 2% 时,把全部邮件判为“正常”,准确率是多少?
- A.接近百分之九十八← 正确答案
- B.接近百分之五十
- C.正好等于百分之百
- D.完全无法计算出来
答案:A。正常邮件占 98%,全判正常则 98% 的样本被猜对,准确率约为 98%。但此时垃圾邮件的召回率为 0,说明准确率在不平衡数据中极具欺骗性。这正是正文强调要看混淆矩阵和精确率、召回率的原因。
Q6. 下列哪些属于邮件数据预处理步骤?
- A.去除邮件中的 HTML 标签← 正确答案
- B.将文本转化为词向量
- C.统一转小写并分词← 正确答案
- D.去掉停用词和噪声符号← 正确答案
答案:ACD。A、C、D 都是把“脏”文本变成干净词序列的预处理操作。B 属于特征提取环节,是把词序列变成数值向量的下一步。预处理好比整理信纸,特征提取好比在信纸上划重点,两者先后有别。
Q7. 关于精确率与召回率的关系,描述最准确的是?
- A.精确率提高则召回率必然提高
- B.二者存在此消彼长的权衡关系← 正确答案
- C.召回率与分类阈值完全没有关联
- D.精确率永远等于模型准确率
答案:B。阈值调高时,模型更保守,拦下的邮件大多“确信是垃圾”,精确率上升,但也会漏掉一些垃圾邮件,召回率下降;阈值调低则相反。因此二者通常呈现 trade-off。A、C、D 都与这种权衡关系矛盾。
Q8. 某词在垃圾邮件中计数 8、垃圾邮件总词数 1000;正常邮件中计数 2、正常邮件总词数 2000,词汇表大小 5000,α=1 时该词在垃圾类的平滑条件概率约为多少?
- A.9/6000 约等于 0.0015← 正确答案
- B.8/1000 正好等于 0.0080
- C.9/1009 约等于 0.0089
- D.9/1003 约等于 0.0090
答案:A。套用拉普拉斯平滑公式 (count + α)/(N + α×V),得 (8+1)/(1000+5000)=9/6000≈0.0015。B 是未平滑的原始统计;C、D 的分母写错。平滑让罕见词概率被压低,这是正常现象,目的是防零概率。
Q9. 垃圾邮件过滤任务在机器学习中属于什么类型?
- A.监督学习的二分类← 正确答案
- B.无监督学习的聚类
- C.自然语言文本分类← 正确答案
- D.深度学习的图像识别
答案:AC。垃圾邮件过滤使用带标注数据训练,输出“垃圾/正常”两个类别,因此既是监督学习二分类,也是文本分类。B 错,因为有标注不是聚类;D 错,输入是文本不是图像。
Q10. 下列部署策略中,最能体现“模型持续更新”的是哪一项?
- A.训练完成后固定参数永久使用
- B.用用户反馈数据定期重训模型← 正确答案
- C.提高服务器 CPU 的硬件规格
- D.把分类阈值固定为 0.5 不改
答案:B。垃圾邮件模板不断变化,固定模型会迅速过时。B 用用户标记数据定期重训,形成反馈闭环,是最典型的持续更新。A 和 D 拒绝变化,C 只是硬件升级,都没有更新模型本身。老王常说的“经验簿要常更新”,正是这个道理。