简介:针对《数据挖掘导论(第二版)》第3章“分类-基础”的配套教学课件,适合数据挖掘初学者、高校师生及相关从业者系统理解分类任务的核心框架。资源以PPTX演示文稿形式呈现,共1个文件,压缩包约1.77MB。课件从分类定义出发,结合训练集与测试集概念,详细展开决策树构建过程、相同数据不同树的辨析,以及Accuracy、Precision、Recall、F1-score等模型评估指标;同时梳理了基于规则分类器、最近邻、神经网络、朴素贝叶斯、支持向量机等基础算法,并介绍Boosting、Bagging、随机森林等集成分类思想。还通过电子邮件分类、肿瘤细胞识别、星系分类等真实案例展示分类任务的应用场景。目前已有809人学习下载,适合配合教材章节进行课内自学或课堂讲解,有助于夯实分类基础并启发后续算法选型思路。 分类是我在数据挖掘这块第一个真正上手落地的基础任务,但说实话,我最初对它的理解远没有想象中深刻。当时按着《数据挖掘导论(第二版)》第3章“分类-基础”的 PPT 自学,觉得决策树、KNN 这些概念都简单,可一到项目里,训练集和测试集怎么切、准确率为什么虚高、过拟合长什么样,全乱成一锅粥。后来回头重看这一章,才发现问题不在算法难,而在基础环节没打通。这篇文章就把我对第3章分类基础的拆解、实操中踩过的坑,以及可直接套用的建模步骤整理出来,给正在啃教材又想动手跑数据集的读者一条相对顺的路。
1. 分类问题的边界:不是“预测”,而是“有监督地做决定”
1.1 训练集、测试集和标签的三角关系
在数据挖掘的任务清单里,分类和回归一样都属于监督学习,但很多人第一次拿到项目时,连“这个任务到底是不是分类”都没想清楚。分类问题的输出是离散的类别标签,比如垃圾邮件/正常邮件、高风险/低风险、恶性/良性;回归问题的输出才是连续数值,比如房价、销量、温度。第3章开篇其实就在做这件事:把分类问题放到监督学习的框架下,强调必须存在已标注的标签集合,没有标签,问题就退化成聚类或异常检测。
正式一点描述:训练集由若干样本组成,每个样本对应一个特征向量 x 和一个类别标签 y,分类器要学习一个从特征空间到类别空间的映射 f(x)。模型建完后,对一个没有标签的新样本,我们用 f 给它一个预测标签。这里很容易忽略的点是,分类器的上限不是由算法决定的,而是由训练数据的质量决定的。数据里如果标签噪声很大,或者特征根本区分不了类别,哪怕后面用十层神经网络也救不回来。第3章里虽然不会直接讲数据清洗,但从“基础”的角度看,先确认标签真实可靠比选算法重要得多。
这个道理,我在一次商品类目识别项目里体会得非常深。客户给的训练样本里,部分商品被人工标错了层级,导致决策树在错误样本上产生了很多奇怪的分支,测试精度怎么也上不去。排查了一天,最后把标签清洗一遍,同一套代码精度立刻提升了十几个百分点。所以学第3章,先别急着调参,第一优先级永远是“标签对不对、数据脏不脏”。数据里藏着多少噪声,模型最终就会尝到多少苦头,这一条放到今天的大模型时代依然成立。
1.2 训练、验证、应用三个阶段的分工
第3章的所谓基础流程,归纳起来就是三个阶段:训练、验证、应用。训练阶段用带标签样本让算法学出 f;验证阶段用没参与训练的数据评估候选模型,并调整超参数;应用阶段把选定的最终模型部署到业务场景,对真实未知样本打标签。很多刚接触分类的人会误以为“训练完直接上线就行”,其实中间的验证阶段才是决定项目成败的关键,它能帮你提前发现过拟合、数据泄漏、超参数不合理等一系列问题。
很多教材为了简化,只写了 train/test 两部分,这在课堂练习里够用,但在真实项目里不够。原因是你一旦在 test 集上反复调超参数,test 就慢慢变成了“见过的数据”,最终评估结果会虚高。我在项目里习惯切成三份:train 用来训练,validation 用来调参,test 只留到最后做一次终极评估。test 集原则上只应该看一次,看完就不要再回头改模型,否则你评价的就不再是模型的泛化能力,而是你和 test 集的拟合能力。
这里补充一个和第3章“分类基础”相配套的实操建议:如果数据带时间属性,划分的时候一定不要随机切,而要按时间顺序切。比如用 1 到 11 月的样本训练,12 月的样本做验证。很多风控和推荐项目,用户行为随时间漂移非常明显,随机切分会让模型在“未来”数据上的表现被严重高估。我第一次做用户流失预测时就是随机切分,上线后效果直接缩水,此后我再也不会忽略这种细节。类似的坑还有:对同一用户的多条记录做切分时,必须把用户维度隔开,否则同一个人既出现在训练集又出现在测试集,评估结果同样失真。
2. 决策树、KNN、朴素贝叶斯:三种基础分类器的选型逻辑
2.1 决策树:从上到下提问,解释性最强
决策树是我在业务汇报时最喜欢的模型,因为它的预测路径可以被写成清晰的 if-then 规则。算法从根节点开始,每次选择某个特征和某个阈值将样本切分,目标是让切分后的子节点比父节点更“纯”。什么是纯?如果一个节点里大多数样本都属于同一类别,我们就认为它在分类意义上很纯。用生活化的话说,决策树就是设计一连串“是/否”问题,把样本一步步引导到对应的答案格子里,整个过程和人做判断的方式非常接近。
第3章里会介绍熵和信息增益的关系:熵表示系统的不确定性,切分后不确定性降得越多,信息增益越大,这个特征就越值得优先作为分裂特征。还有一种分裂准则是基尼指数,它衡量从一个节点随机抽取两个样本类别不一致的概率。实际开发中我们用 sklearn 的 DecisionTreeClassifier,通过 criterion 参数切换 gini 或 entropy,两者在多数场景下差异不大,不必过度纠结。真正需要花心思的是控制树的大小,而不是纠结这两个指标之间那零点几个百分点的差距。
我习惯先把 max_depth 设成 3 到 5,看训练和验证的分数差距。iris 数据集上,深度 3 的树通常已经能取得不错的效果,而且画出来的树很直观。对应的代码特别简单:
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier data = load_iris() X, y = data.data, data.target X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42 ) clf = DecisionTreeClassifier(max_depth=3, criterion='gini') clf.fit(X_train, y_train) print("train acc:", clf.score(X_train, y_train)) print("test acc:", clf.score(X_test, y_test))跑完通常会发现 test acc 不会比 train acc 低很多,因为深度限制在 3 的树复杂度有限,反而不容易记住太多噪声。如果我把 max_depth 改成 10,train acc 会冲到接近 100%,test acc 反而可能下滑,这就是过拟合最直接的一个演示,也是第3章里“模型复杂度-泛化误差”曲线想表达的东西。实际业务上除了深度,我还会调 min_samples_split、min_samples_leaf,这两个参数能限制节点继续分裂所需的最少样本量,本质上也是在给树“减肥”。
2.2 KNN:距离投票,简单但容易受特征尺度影响
KNN 是很多人最早接触的“非参数”方法。它的学习过程几乎为零,预测时才拿新样本和训练样本逐一算距离,取最近的 K 个邻居对类别投票。我在第一次跑 KNN 时,最大的疑惑是“这也能叫训练?” 是的,训练阶段只需要把样本存下来,预测阶段做计算。这种惰性学习的优点是实现简单、决策边界非常灵活,缺点是预测阶段慢,而且受特征尺度影响极大。第3章把它作为基础算法,其实正好暴露了很多分类任务的共性:很多东西看着简单,真正用起来满身是刺。
举一个很常见的例子:假设特征包括年龄(0-100)和收入(5000-50000),在欧氏距离里,收入差 5000 对距离的贡献是年龄差 50 的 100 倍,年龄这个特征就被完全淹没了。所以用 KNN 前必须做标准化或归一化。sklearn 里通常用 StandardScaler:
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)注意这里必须先把 scaler 在训练集上 fit,再用同一个 scaler 去 transform 测试集,不能用测试集单独 fit,否则相当于把测试集信息提前泄漏给了模型。如果场景里特征分布没有明显长尾,也可以用 MinMaxScaler 把数据压缩到 0 到 1 之间,但 StandardScaler 对异常值更稳健一些,是我更常用的选择。
另一个重点是 K 的选择。K 太小,模型容易跟着个别噪声样本走;K 太大,距离远的异类样本也被拉进多数表决。常见做法是用交叉验证搜索 1 到 30 之间的 K 值。wine 数据集做 KNN 分类是很经典的练习,13 个数值特征、3 个类别,标准化后选对 K,准确率很容易做到 95% 以上。这个例子也提醒你:KNN 的好坏,很大程度上取决于特征工程的功夫,特征缩放、去冗余、降维,每一步都可能比调 K 影响更大。
2.3 朴素贝叶斯:概率底座,天生适合高维文本
朴素贝叶斯放在第3章的基础分类器里,是因为它提供了另一种完全不同的视角:不直接构造决策边界,而是计算后验概率 P(y|x),样本属于哪个类别的概率高就分到哪个类别。根据贝叶斯定理,P(y|x) 可以通过先验 P(y) 和似然 P(x|y) 来估计。为了让估计可行,朴素贝叶斯假设特征之间条件独立,这就是“朴素”一词的由来。你可以把它理解成一位很“天真”的评委:它认为每个证据都在独立地支持某个结论,不考虑证据之间的复杂关联。
这个假设现实中很少成立,但它在文本分类、垃圾邮件识别上非常好用。原因是文本特征经常是高维稀疏的词频向量,如果不对特征做独立假设,联合概率几乎无法估计;一旦用了条件独立假设,每个词的贡献可以单独统计,训练速度快到惊人。sklearn 里的 MultinomialNB 通常搭配 CountVectorizer 或 TfidfVectorizer 使用,完整流程就是“词频统计 -> 向量化 -> 朴素贝叶斯训练”。很多公开的“朴素贝叶斯模型用于垃圾邮件分类-sklearn版”项目,核心就是这套流程,跑起来非常快,也容易调通。
与决策树和 KNN 相比,朴素贝叶斯对缺失数据、小样本也更友好,但它的短板同样明显:特征强相关的场景下,概率估计会失真。比如在图像分类里,像素之间高度相关,朴素贝叶斯往往拼不过别的模型。所以选不选它,先看特征是否大体独立,或者你是否能接受这种近似。做文本、做大规模标签体系时,它常常是性价比最高的起手式。
2.4 基础分类器的横向对比
| 算法 | 学习方式 | 主要优点 | 主要缺点 | 典型场景 |
|---|---|---|---|---|
| 决策树 | 急切学习 | 可解释性强,能同时处理数值和类别特征 | 容易过拟合,结构对数据变化敏感 | 风控规则、运营分层 |
| KNN | 惰性学习 | 实现简单,无需训练阶段 | 预测慢,特征尺度影响大 | 小样本分类、推荐 |
| 朴素贝叶斯 | 急切学习 | 训练快,适合高维稀疏特征 | 强独立假设,估计可能失真 | 文本分类、垃圾邮件识别 |
表格只能给你一个初筛方向。真正到了项目里,我一般会把这三种模型全部跑一遍,用同一套交叉验证流程打分,再看业务上更看重可解释性还是精度。第3章的意义就在于,你至少得知道每个模型的基本脾气,才能在初筛时不至于乱选。这个表也不是一成不变的,比如决策树和 KNN 的缺点可以通过集成方法、距离加权等方式缓解,但那已经超出基础范畴了。
3. 过拟合、评估指标与交叉验证:最容易被跳过却最重要的部分
3.1 训练精度高不代表模型好
第3章把过拟合放在很重要的位置,因为它是几乎所有分类算法共同的敌人。过拟合的本质,是模型把训练数据里的噪声当成规律学进去了,导致训练集上表现很好,换一批数据就露馅。为什么会出现这种情况?因为模型的能力太强了,可以记住每一个训练样本的细节,而不是提炼出更通用的规律。越复杂的模型越容易陷入这种“死记硬背”的状态,这也是为什么“奥卡姆剃刀”原则在机器学习里会被反复提起。
用一个生活化的类比:一个学生如果靠死记硬背把作业本上的题目答案全背下来,作业正确率能到 100%,但考试题目稍一变化,他就蒙圈。而另一个学生只理解了核心公式,作业正确率也许只有 90%,但考试照样能解题。分类器也是一样,训练精度高不一定等于泛化好,甚至有时候略低的训练精度反而代表模型找到了更本质的规律。所以第3章反复强调,评估模型要看它在“没见过的数据”上的表现,而不是看它对旧数据记得多牢。
实践里怎么识别过拟合?最直接的办法就是比较训练分数和验证分数。如果训练 acc 95%、验证 acc 只有 80%,基本可以认为过拟合了。决策树出现这种情况时,我会先降 max_depth,调大 min_samples_leaf,或者加一些剪枝策略。KNN 的 K 值过大或过小也会呈现类似症状,K 太小容易过拟合,K 太大则倾向欠拟合,交叉验证就能帮你找到合适的中间值。要记住:训练集上的分数是“下限”,验证集上的分数才更接近真实,不要被前者蒙住眼睛。
3.2 准确率会骗人:混淆矩阵和四个基础指标
分类评估不能只盯准确率。二分类里,我们把预测结果和真实结果放在一起,能得到四个格子:TP(真正例)、FP(假正例)、FN(假负例)、TN(真负例)。基于这四个数值,准确率、精确率、召回率、F1 分别从不同角度描述模型表现。第3章讨论的也是这套体系,但在实际业务项目中,很多人还是习惯只看 accuracy,这很危险。准确率只回答了一个很粗的问题:“整体上有多少预测对了”,它掩盖了不同类别之间的巨大差异。
举一个我实际遇到过的例子:一个信用卡欺诈检测数据集,只有不到 1% 的样本是欺诈,如果模型把全部样本都判为正常,准确率高达 99% 以上,看起来非常漂亮,但它没有识别出一笔欺诈交易。这个模型没有任何应用价值。所以做分类评估,尤其是类别不平衡场景,至少要看精确率和召回率。精确率回答的是“你预测出来的正类里有几个是对的”,召回率回答的是“真实的正类里有几个被你找回来了”,F1 则是对两者的加权平衡,适合在精确率和召回率都重要时作为一个综合分数。
sklearn 里打印一份完整报告非常方便:
from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test, clf.predict(X_test))) print(classification_report(y_test, clf.predict(X_test)))看这份报告时,先确认类别是否均衡,再决定以哪个指标为主要优化目标。业务是防止“漏掉坏人”,就主看召回率;业务是避免“误伤好人”,就主看精确率。至于准确率,只有在各类别样本量接近的时候才适合当第一参考。多分类场景则通常看 macro 平均或 weighted 平均,前者对每个类一视同仁,后者按样本量加权,两者侧重点不同,写报告时要说明清楚。
3.3 交叉验证:把“调参”这件大事科学化
既然测试集只能看一次,调参时我们就需要另一个更稳健的评估方式:交叉验证。最常见的是 K 折交叉验证。把训练集切成 K 份,每次用其中 K-1 份训练、1 份验证,循环 K 次取平均。这样每个样本都参与过训练也参与过验证,得到的分数比单次划分更稳定,也不会因为某一次划分运气好或坏而产生误导。第3章里的“模型评估与选择”,落到代码层面就是这一套东西。
sklearn 的接口很简单:
from sklearn.model_selection import cross_val_score scores = cross_val_score(clf, X_train, y_train, cv=5) print(scores.mean(), scores.std())这里有一个容易忽略的细节:对分类任务,折数划分时最好用分层策略,也就是每一折里各类别比例要和整体数据大致一致。如果数据里某个类别占比很低,随机划分可能导致某几折里根本没有这个类别,评估结果会忽高忽低。sklearn 的 cross_val_score 在传给分类器时默认会做分层,但我们自己写手动交叉验证,就要注意用 StratifiedKFold 来切分。
我实际调参时会写一个循环,把决策树的 max_depth、KNN 的 n_neighbors 等候选值逐一跑交叉验证,打印出每个参数组合的均值与标准差。均值代表模型的平均能力,标准差代表稳定性。标准差太大,说明模型对特定数据划分很敏感,通常需要降低复杂度或者检查特征质量。如果你发现某个参数的候选值之间分数波动很厉害,别急着追求更高的均值,先想想为什么不稳定,往往数据问题要比参数问题更值得排查。
4. 我在真实项目里踩过的分类基础坑
4.1 类别不平衡:看似不错的模型其实什么都没学到
这是我职业生涯里印象最深的一次翻车。当时做一个逾期用户预测,逾期样本占比只有 3%。我第一次提交的模型,整体准确率跑到了 97%,心里还挺得意。后来被同事提醒看了一眼混淆矩阵,才发现模型把所有人都预测成“不逾期”,逾期样本一个都没识别出来。换句话说,这个模型学到的策略就是“躺平”,因为策略本身就能带来高准确率。这个场景放在分类基础里,就是典型的“再好的指标也要结合业务背景解读”。
第3章虽然在基础层面不会展开太多类别不平衡的解决手段,但“用准确率评估分类器”这个习惯必须在基础阶段就被纠正。后来我在模型里加了 class_weight='balanced',对少数类错误赋予更高惩罚;在数据层面也尝试过对多数类进行下采样,让训练集的类别比例接近五比五。改完之后,准确率虽然跌到了 90% 出头,但真正有业务意义的召回率从上去了。如果你想让实验更充分,还可以对少数类做 SMOTE 类的合成采样,但要注意只能在训练集上做,不能对测试集做同样的合成。
这个坑给初学者的启示是:看结果不要只看一个数字。打印混淆矩阵、看各类别的 precision/recall,才是对模型做“体检”的正确方式。教材里的混淆矩阵那一页很不起眼,实际救了我一整个项目。后来我带新人时,要求他们每次跑完模型必须顺手打印 classification_report,养成习惯后很多离谱的模型都不会被提交到评审会上。
4.2 特征尺度不一致,KNN 被单一特征绑架
另一次做商品分类,特征包含商品数量、价格、评分。商品数量可能是几十到几百,价格可能是几元到几百元,评分只是 1 到 5 的整数。我一开始直接跑 KNN,结果无论怎么调 K,分类结果都很奇怪。后来把每个特征的分布打印出来才发现,欧氏距离几乎被“数量”这一个特征统治,价格和评分对邻居选择的贡献微乎其微。就像一个评审团里有人嗓门特别大,其他人的意见全被压住了,投票结果自然不客观。
解决方式就是标准化,把所有数值特征都转换到均值 0、方差 1 的分布。标准化之后,三个特征在距离计算中才有了相对合理的话语权,模型效果立刻好转。这个故事再次说明第3章里 KNN 的小字部分有多重要:基于距离的算法,必须配合特征缩放。不是说决策树或朴素贝叶斯完全不受特征尺度影响,但它们对尺度不像 KNN 这么敏感。决策树做分裂时只关心阈值比较,特征整体放缩不会改变相对顺序;朴素贝叶斯在简单实现里会估计分布参数,尺度变化也主要影响数值稳定性,而不像 KNN 直接改变距离总和。
4.3 不是所有项目都要冲最高精度:可解释性决定了能走多远
我在银行类项目里常被业务人员追问:为什么这个客户被判成高风险?如果你用的模型是一个深度黑箱,这个问题几乎没法回答。哪怕模型在验证集上精度再高,业务方不信任,就上不了线。所以第3章把决策树放在基础分类器第一位,是有现实考量的:树模型天然可以输出从根到叶子的路径,让人理解判断依据。业务方看到“收入低于 5000 且近三个月有三次逾期”这样的规则,会立刻给出“合理”或“不合理”的判断,这是黑箱模型给不了的反馈。
我的习惯是,先训练一棵深度较小的决策树,把关键分支整理成业务规则文档,和业务方对齐“模型逻辑是否合理”。逻辑合理了,再去考虑用更复杂的模型提升精度。这样做虽然多了一道流程,但能极大降低后期沟通成本。很多新人以为分类项目就是“算法选最强的”,我在实际项目里体会是:算得清、讲得明白,往往比精确几个百分点更重要。尤其是在强监管、强合规的行业里,可解释性不是加分项,而是准入门槛。
5. 从PPT到可运行项目:给新手的几步实操建议
5.1 一套可以直接抄的建模骨架
如果你目前正在看第3章,想拿一个小数据集练手,我推荐按下面这个骨架走。它不炫技,但能保证你不会漏掉关键环节。这个流程不是我发明的,而是从很多踩坑经历里倒推出来的:先划清数据边界,再决定预处理,然后用交叉验证选参数,最后在真正的测试集上做一次“考试”。
from sklearn.model_selection import train_test_split, cross_val_score from sklearn.preprocessing import StandardScaler from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import classification_report # 1. 划分数据,stratify 保持类别比例 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, stratify=y, random_state=42 ) # 2. 预处理:KNN/SVM 等基于距离的算法需要标准化 scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) # 3. 用交叉验证调超参数 for depth in [3, 5, 8, 10]: clf = DecisionTreeClassifier(max_depth=depth) scores = cross_val_score(clf, X_train, y_train, cv=5) print(f"depth={depth}, acc={scores.mean():.3f}±{scores.std():.3f}") # 4. 用最优参数在训练集上重新训练,并在测试集上做最终评估 clf = DecisionTreeClassifier(max_depth=3) clf.fit(X_train, y_train) print(classification_report(y_test, clf.predict(X_test)))注意几个细节:stratify=y 让训练集和测试集的类别比例保持一致;scaler 只能用训练集拟合,再用来转换测试集,避免测试集信息提前泄漏;交叉验证的目的是选参数,最终模型训练好之后,测试集只能做一次终极验证。如果你想在项目中更省心,也可以把预处理和模型塞进 sklearn 的 Pipeline,这样网格搜索时就不会忘记对每一折都单独做预处理:
from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV pipe = Pipeline([ ('scaler', StandardScaler()), ('clf', DecisionTreeClassifier()) ]) params = {'clf__max_depth': [3, 5, 7]} grid = GridSearchCV(pipe, params, cv=5) grid.fit(X_train, y_train)用 Pipeline 的好处是,预处理这一步被封装进交叉验证循环里,每一折都会用当前训练折重新 fit scaler,不会出现数据泄漏。这个细节很多教材不屑于讲,但在真实比赛中和项目里非常关键。
5.2 把基础打牢之后再往哪个方向走
第3章讲的是“分类-基础”,后续章节一般会继续展开贝叶斯分类器、规则分类器、模型评估与选择等内容。学完这一章之后,我建议不要急着铺开深度学习,先把决策树、KNN、朴素贝叶斯三个模型玩熟,理解它们的输入嗜好、评估方式和过拟合症状。之后再接触支持向量机、随机森林、XGBoost、神经网络时,你会发现它们解决的仍然是同一件事,只是在“怎么切分、怎么组合、怎么评估”上做了更复杂的设计。
最后再分享一个我保留到现在的习惯:每次建模,都会把预测错误的样本单独打出来,一条一条看。这个动作看起来原始,但能发现非常多标签错误、异常值、特征交叉规律,这些信息往往比调参更能提升模型效果。分类基础不是“背概念”,而是通过这些枯燥的基础动作,慢慢建立对数据的直觉。第3章只是一个起点,真正扎实的功夫,都在起点之后的一排排错误样本里。
本文还有配套的精品资源,点击获取