机器学习里有一类问题,几乎占了业务场景的大半壁江山,就是分类。垃圾邮件识别、信用卡欺诈检测、图片内容识别、疾病风险预测、用户流失预警,这些看似风马牛不相及的领域,落到算法层面,核心都是同一件事:给定一个样本,判断它属于哪一个类别。这篇笔记是机器学习系列第三篇,专门聊分类问题。我会从分类任务的定义讲起,把常见的分类算法挨个过一遍,说清楚它们各自擅长什么、短板在哪,再重点讲讲实际工程里最要命的评估指标选择和数据处理坑点。适合刚看完回归问题、准备进入分类领域的学习者,也适合正在做期末复习、需要把零散知识串成体系的同学。内容偏实战,数学推导只保留最核心的直觉,尽量让你读完就能上手,而不是停留在背公式的层面。
1. 分类问题的本质:从这个例子你就懂了
1.1 一张表搞懂分类和回归的边界
很多新手最大的困惑不是“分类怎么实现”,而是“什么时候该用分类,什么时候该用回归”。有个特别直观的判断方式:看输出值有没有“顺序含义”。房价预测,3万一平和5万一平之间是连续的、可比较的,这是回归。天气预测明天是否下雨,只有“下雨”和“不下雨”两种结果,你不能说“下雨”比“不下雨”大多少,这是分类。再比如预测一个用户会不会流失,“会”和“不会”没有大小之分,这也是分类。
严格一点说,分类问题的训练集长这样:
输入特征 x1, x2, ..., xn 输出标签 y ∈ {C1, C2, ..., Ck}目标是学到一个映射函数 f(x) → y,让新来的样本能够被自动归入正确的类别。二分类是最基础的情形,也就是 y 只取两个值,通常记作 0 和 1(或者 -1 和 +1)。多分类可以看作二分类的扩展,做法上要么是“一对多”,要么是“一对一”,后面细聊。
1.2 为什么回归模型不能直接拿来分类
有人会问:既然线性回归能输出一个数值,那加个阈值不就能做分类了吗?比如输出大于 0.5 判为正类,小于 0.5 判为负类。理论上确实可以这么做,但实际上一旦遇到异常值就很容易翻车。回归模型的目标是最小化所有样本的均方误差,这意味着它会被那些偏离很远的样本强烈牵制。
我之前做个一个很简单的演示,拿一组带明显离群点的数据跑线性回归,再把输出切分成两类,结果分类边界被那个离群点拽得歪七扭八,准确率直接从 90% 掉到 70%。原因在于回归的损失函数是“差多少算多少”,而分类更关心的是“方向对不对”。你预测 0.6 和预测 0.9,只要都超过阈值,判的都是正类,但回归会硬要把 0.6 拧到 0.9 附近,白白浪费模型容量。这就是为什么分类需要专门的模型和专门的损失函数。
2. 六大核心分类算法选型指南
这一节我按“原理直觉 → 适用场景 → 关键参数”的结构,把最常见的分类算法逐一拆解。注意我没有按“谁更先进”排序,而是按“你应该从哪个学起”来排。
2.1 逻辑回归:名字里带回归,却是分类的头号主力
逻辑回归虽然名字里有“回归”两个字,但它是个彻彻底底的分类算法。它的核心思路是:先把线性组合的结果通过 Sigmoid 函数压缩到 (0,1) 区间,得到样本属于正类的概率,然后设一个阈值(通常 0.5)做判定。
Sigmoid 的公式是:
p = 1 / (1 + exp(-z)) z = w1*x1 + w2*x2 + ... + b这个设计妙在哪?Sigmoid 在 z=0 附近斜率大,稍微变化一点,概率就明显波动,这让决策边界附近的样本对模型参数特别敏感;而在远离边界的地方,概率被压到接近 0 或 1,梯度趋近于零,模型会自动“不太关心”那些已经分得很清楚的样本。这种特性特别适合分类——模型把主要精力集中在边界附近。
实操层面,逻辑回归的三个要点:
- 特征必须做标准化或归一化,尤其当特征量纲差异大的时候(比如一个特征是年龄,另一个特征是收入),否则梯度下降收敛会特别慢。
- 用正则化控制过拟合,常用 L2,特征极多且稀疏时用 L1(还能顺便做特征选择)。
- 决策阈值不一定要用 0.5。如果业务更看重“别漏掉正例”,可以把阈值调低;更看重“预测为正的得准”,就调高阈值。后面讲评估指标时细说。
逻辑回归的优点是训练快、可解释强,系数直接告诉你每个特征对风险概率是正向还是负向作用。短板是决策边界是线性的,遇到非线性数据需要自己构造交叉特征或高阶特征,否则性能天花板很低。如果你刚入门,建议无论如何先跑通一个逻辑回归作为 baseline,再对比其他模型的提升幅度。
2.2 决策树:一边问问题,一边做决定
决策树的思路最好理解——它模仿人类做决定的过程。根节点先问一个最优问题,比如“年龄是否大于 30?”,是的走左边,不是走右边,每个节点再继续问下一个问题,直到把样本分到叶子节点,叶子节点的类别就是预测结果。
关键在于“每次问什么问题、以什么顺序问”。常见的选择标准有两个:ID3/C4.5 用信息增益(Information Gain),CART 用基尼系数(Gini Impurity)。两者的逻辑都是追求“分完之后,子节点内部更纯”。我用基尼举例,某个节点的基尼不纯度计算方式:
Gini(D) = 1 - Σ(p_i)^2完美分类时,某个类别概率为 1,Gini=0;类别均匀分布时,Gini 最大,说明“最混乱”。选出那个能让 Gini 下降最多的特征和阈值作为当前的划分点。
决策树的优势是几乎不需要特征标准化,能自动处理数值型和分类型特征,模型天然可解释——可视化之后直接就是规则集。但它有个臭名昭著的毛病:单棵树极其容易过拟合,只要树足够深,它能把训练样本记到“背下来”的程度。控制手段包括限制最大深度(max_depth)、限制叶子节点最少样本数(min_samples_leaf)、限制分裂最少样本数(min_samples_split)。
实际使用中,我基本不用单棵决策树做最终模型,都是拿它当集成学习的基学习器用。但理解决策树本身非常重要,因为随机森林和梯度提升树的底层都建立在“用树划特征空间”这个思想上。
2.3 支持向量机:找一条最稳健的边界
SVM 的直觉很有意思,之前那些算法都是“找一条能分开两类的线就行”,SVM 会追问一句:“哪条线最好?”它的答案是:距离两边最近的样本点都最远的线——也就是“最大间隔”的那一条。那些恰好站在间隔边缘上的样本点被称为支持向量,它们决定了最终模型长什么样。
这里最容易让新手困惑的是“核技巧”。所谓核函数,本质是“把样本从低维映射到高维,让原本线性不可分的数据变得线性可分”,但计算时不需要真的去算高维映射,直接用核函数就能得到高维空间里的内积结果。最常见的几个核:
| 核函数 | 适用情形 | 关键参数 |
|---|---|---|
| 线性核 | 数据量大、特征维度高、线性可分 | C |
| 多项式核 | 有先验的多项式关系 | degree, C, coef0 |
| RBF(高斯核) | 特征维度适中、非线性强 | C, gamma |
RBF 是最常用的默认选择,但 gamma 这个参数非常敏感。gamma 太大,每个样本的影响范围很小,边界非常曲折,容易过拟合;gamma 太小,影响范围过大,边界过于平滑,容易欠拟合。调 gamma 和 C 没有捷径,老老实实画学习曲线,或者用网格搜索。
SVM 的另一个痛点是训练复杂度。经典的 SMO 算法还好,但当样本量上了十万级,用 scikit-learn 里的 SVC 训练速度会明显变慢。样本量大的时候我更倾向于用 SGD 版本的 SVM,或者干脆换树模型。
2.4 K近邻:最懒的算法,最实用的兜底方案
KNN 恐怕是最没有“训练过程”的算法。它不学习任何参数,把训练数据记下来,预测的时候拿新样本和所有训练样本算距离,挑距离最近的 K 个样本,投票决定类别。距离通常用欧氏距离,但计算前一定要做特征缩放,不然特征 A 的量纲是 0~1,特征 B 的量纲是 0~10000,B 会完全主导距离计算。
K 值的选择直接决定偏差方差平衡。K 太小,只参考最近的一个样本,对噪声极度敏感;K 太大,把远处很多不相关样本也拉进来投票,边界被抹平。一个粗略的经验规则是 K 取奇数(避免平票),然后用交叉验证选值,别拍脑袋。
KNN 的实际应用场景主要是推荐系统(找相似用户)、异常检测这些小规模任务。它的缺点在高维场景下尤其明显——高维空间里所有样本的距离都差不多,“最近邻”不再有区分度,这种现象叫“维度灾难”。在面试中这是一个高频追问点,记住:KNN 在特征维度超过 20 甚至更少的时候就要小心了。
2.5 朴素贝叶斯:算概率,但做了个“天真”的假设
朴素贝叶斯基于贝叶斯定理,核心是计算后验概率 P(类别 | 特征),然后挑概率最大的类别。公式写出来很简单:
P(C|X) = P(C) * P(X|C) / P(X)分母 P(X) 对所有类别都是一个常数,比大小的时候可以忽略。真正麻烦的是 P(X|C)——在特征维度很高的时候,联合概率分布根本没法从有限样本里估计。朴素贝叶斯的“朴素”之处,就是假设所有特征在给定类别条件下是相互独立的,于是:
P(X|C) = P(x1|C) * P(x2|C) * ... * P(xn|C)这个假设在实际数据中几乎不可能严格成立——比如一封邮件里“免费”和“点击”两个词显然不是独立的。但神奇的是,即便假设不成立,朴素贝叶斯在很多任务上的表现依然能打,尤其适合文本分类。
实际使用时的三个注意点:连续特征要假设分布形式(通常高斯分布);概率算出来经常极小,工程实现都用对数概率避免下溢;如果某个特征在某个类别下没出现过,概率为 0 会直接毁掉整条乘积链,所以必须做拉普拉斯平滑,也就是在计数上加个小常数。
我自己的经验是,朴素贝叶斯最适合做“快速上线的文本分类方案”。当线上资源紧张,或者数据只有几百条标注样本,朴素贝叶斯往往比复杂模型跑得更稳更省事。
2.6 集成学习:把一堆弱模型拧成一股绳
集成学习是目前工业界最实用的一套方法论,核心就一句话:“三个臭皮匠,顶个诸葛亮”。随机森林和梯度提升树是最常用的两大流派,它们的思路差异非常关键。
随机森林属于 Bagging。它同时训练多棵决策树,每棵树用有放回抽样(Bootstrap)得到的不同子集训练,每棵树做分裂时只从随机选取的特征子集里找最优特征。这相当于“让每棵树各看一面,然后集体投票”。随机性保证了树和树之间的差异足够大,投票之后方差被显著压低。它对异常值和噪声的容忍度很高,调参压力小,默认参数通常就表现不错。
梯度提升树属于 Boosting。它挨个训练树,后一棵树专门去拟合前一棵树没搞定的残差。XGBoost、LightGBM、CatBoost 都是这个思路的工程优化版本。Boosting 的拟合能力极强,几乎是目前表格数据上默认的最强方案,但代价是对噪声比较敏感——如果数据里有很多标注错误的样本,Boosting 会努力去拟合这些错误,反而把模型带偏。这时候要么清洗数据,要么调低学习率、增加正则项来抑制过拟合。
选型建议是这样的:数据集干净、想要最高精度,优先 XGBoost/LightGBM;数据里有不少噪声、想要稳健结果,优先随机森林;业务上需要解释特征重要性,两者都能给,但随机森林的重要性估算更稳定。
3. 评估指标:分类模型好不好的唯一裁判
分类模型的评估比回归复杂得多。回归看一个 R² 或 MSE 就行,分类却有一整套指标体系。最大的坑是:准确率(Accuracy)并不是万能的。我当时第一个分类项目就用准确率做唯一指标,结果在严重不平衡的数据上做出了 95% 的“好成绩”,细看才发现模型把所有样本都预测成了多数类——这个模型本质上是个废品。
3.1 混淆矩阵与四个核心指标
混淆矩阵是理解一切分类指标的地基。二分类场景下,把真实类别和预测类别两两组合,得到四种情况:
| 预测为正类 | 预测为负类 | |
|---|---|---|
| 真实为正类 | TP(真正例) | FN(假负例) |
| 真实为负类 | FP(假正例) | TN(真负例) |
基于这四个数字,可以算出一组指标。准确率(Accuracy)= (TP+TN) / 总数,只能看整体对错。精确率(Precision)= TP / (TP+FP),回答“你预测为正的那些里,有多少是真对的”,重视的是少报假警报。召回率(Recall)= TP / (TP+FN),回答“真正的正例里,你捞回了多少”,重视的是别漏掉目标。F1 值是精确率和召回率的调和平均,公式:
F1 = 2 * Precision * Recall / (Precision + Recall)3.2 指标选择必须跟着业务走
评估指标从来不是数学问题,而是业务问题。做信用卡反欺诈,正类是“欺诈交易”,每十万笔里可能只有几笔是欺诈,你宁愿把很多正常交易拦下来引发用户投诉,也不想让一笔欺诈溜过——这时候召回率优先,F2(召回权重更高)比 F1 更合适。做搜索排序,用户搜“iPhone”你返回的十条结果里如果混进三条“手机壳”,用户直接划走,这时精确率优先,宁可少推荐也不能推荐错。做医学筛查,漏诊的后果远严重于误诊,也是召回率优先。
阈值的移动直接改变精确率和召回率的权衡:阈值调高,预测为正的门槛变高,正例预测少了,精确率升、召回率降;阈值调低,正例预测多了,召回率升、精确率降。ROC 曲线和 PR 曲线就是描述这种权衡的工具。
具体比赛中优先看 PR 曲线,因为类别不平衡时 ROC 曲线容易过于乐观;数据相对均衡,ROC-AUC 可以放心用。AUC 的含义是“随机抽一个正样本和一个负样本,模型给正样本打分更高的概率”,AUC=0.5 相当于瞎猜,AUC=0.8 以上是比较理想的状态。
3.3 多分类的评估要点
多分类的评估思路是先把多分类拆成多个二分类再看。最简单的是 macro 平均,每个类分别算指标再取平均,这种办法平等对待每个类别,但会被小类别的表现拖累。加权平均(weighted)按各类样本数加权,更像整体视角。如果你的任务存在严重类别不平衡,最好每个类单独看,尤其关注样本最少的那个类的精确率和召回率。那种“全局准确率 92%”的漂亮数字,在小类别上可能是 20% 的召回率,一叶障目。
4. 真实项目里避不开的数据问题
算法只占项目的一部分,真实数据比课本数据脏得多。这一节讲三个高频问题:噪声、类别不平衡、特征工程。每一个单独拎出来,都可能比调模型更影响最终效果。
4.1 噪声数据,先清洗再谈训练
噪声数据指三类情况:标注错误、特征取值异常、重复或矛盾样本。标注错误最常见也最致命——分类是靠标签学习的,标签错了,模型就是错的。检测标注错误的一个简单办法:先用随机森林训练,拿到每个样本的预测概率,把“预测概率很高但真实标签相反”的样本拎出来人工审查。其实就是用模型的“惊讶”来找疑似错误标注,能省下大量人工翻数据的精力。
特征取值的异常一般分成两种情况。连续特征超出正常范围的极端值,能真的确认是录入错误就替换或删除,否则做一次极值裁剪(比如把超过 99.9 分位数的值截断),比留着强。类别特征出现“训练集没见过的新值”,在预测阶段经常直接崩掉,稳妥的办法是统一归为“未知”类别,让模型学一个“未知”的应对方式。
这里必须强调:噪声处理不是越激进越好。我见过有人把离群点全删了,结果模型在真实场景表现很差——因为真实场景全是离群点。删之前先搞清楚这个异常值是测量误差还是真实存在但少见的极端情况。拿不准的时候,优先对树模型更友好(它对个别离群点不太敏感),或者改用鲁棒性更强的损失函数。
4.2 类别不平衡:别让多数类统治你的模型
不平衡问题的根源在于模型默认目标是“整体准确率最大化”,少数类贡献的错误比例太小,被整体损失稀释,模型直接摆烂把所有样本都归为多数类,照样拿高准确率。
应对手段从数据层面讲,过采样(复制少数类样本)、欠采样(丢弃多数类样本)、SMOTE(在少数类样本之间插值生成新样本)是三大常规操作。SMOTE 比简单复制更聪明——它在相邻的少数类样本连线上合成新样本,增加了样本多样性。但要注意,SMOTE 不能跨验证集,否则会把合成样本的信息泄漏进验证过程,得到虚高的分数。
从算法层面讲,一个最直接的改动是给模型加类别权重,scikit-learn 里几乎所有分类器都有 class_weight='balanced' 选项,原理是让少数类的误分类惩罚更大。XGBoost 里对应的是 scale_pos_weight 参数。这个改动通常比你费劲采样效果更直接,而且几乎不增加代码成本。
我的处理顺序是:先调 class_weight,不行再说采样;采样的优先级是 SMOTE 优先于过采样,过采样优先于欠采样。欠采样虽然能加速训练,但丢数据丢得心疼,只有在数据量足够大的时候才考虑。
4.3 特征工程与标准化:这件事值得花一半时间
特征工程是机器学习项目里被讨论最少但收益最高的一件事。我的经验是,新手容易把时间全花在调模型参数上,但真正让准确率从 0.8 涨到 0.9 的往往是特征。
几个基础操作按优先级排:数值特征做缺失值填充(中位数比均值更抗离群点)、类别特征做目标编码或独热编码、长尾分布的特征做对数变换,把偏态拉正。有些特征虽然单看和标签关系不大,但把两个特征组合成“比例”反而有信息量,这种需要结合业务去思考,比如“消费金额 / 消费次数”得到客单价,比两个原始特征分开给模型更高效。
标准化这件事,逻辑回归、SVM、KNN 这类基于距离或梯度的模型必须做;决策树和随机森林不需要;梯度提升树也不需要。做标准化时保证只基于训练集的统计量,再应用到验证集和测试集,搞反了就是数据泄漏。
5. 从零到一:怎么学好分类问题
分类问题学得好不好,不在于能背出多少个算法的公式,而在于能不能在遇到新数据集时快速做出体系化的决策:数据是干净还是脏?类别是否平衡?特征是什么类型?该选树模型还是线性模型?该用哪个评估指标?这些决策链条贯穿每一个真实项目。
如果你是自学、准备期末、或者刚开始找机器学习相关工作,我给的路径是:先用逻辑回归和决策树跑通分类流程,掌握混淆矩阵、精确率召回率这些概念,然后在 Kaggle 或天池上找一个表格类的二分类比赛,完整走一遍数据处理到模型的流程。接着尝试把随机森林和 XGBoost 跑起来,观察在同一个数据集上的效果差异,把调参经验记录下来。最后再回头看 SVM 和朴素贝叶斯——这两个算法目前用得少,但面试高频、概念经典,忽视不得。
课程资源方面,吴恩达的机器学习课程里分类部分讲得清楚,适合建立整体直觉;李航的《统计学习方法》适合推敲细节,尤其 SVM 的推导值得反复看。上手练习的话,可以在本地装好 scikit-learn,把 iris 或手写数字数据集玩熟,也可以用一些在线实训平台分步闯关。这里我不推荐只刷题不跑实验,分类的很多坑(比如 class_weight 加了反而掉分、标准化忘了做导致 SVM 收敛慢)都是“做了才知道”的经验型知识。
期末考试自习的话,把握三条主线:第一,每个算法回答“它解决什么问题、它的假设是什么、它的损失函数长什么样、它怎么防止过拟合”,四个问题能答得上来基本够用;第二,把评估指标的定义和公式默写出来,尤其能够在给定混淆矩阵时手算 Precision、Recall、F1;第三,能画出决策树、SVM、随机森林之间的关系图谱——是从哪出发、为了解决什么问题、用什么策略改进。主线通了,细节查漏即可。
最后再分享一个小技巧。我之前做分类项目时,养成一个习惯:任何模型先建立一个“极度简单的 baseline”,比如用全部特征训练逻辑回归、固定评估指标、固定随机种子。后面每次改进都要和这个 baseline 对比。这样做的好处是你能清楚知道每个操作(特征工程、调参、换模型)到底带来了多少提升,而不是糊里糊涂地跑出一堆结果却不知道哪个操作起了作用。有一次我把特征工程做完,发现逻辑回归从 0.85 涨到了 0.91,这个上涨幅度甚至超过了后来 XGBoost 调参的效果。这件事给我的教训很深:分类问题的天花板往往不在模型,而在数据和特征的理解上。希望你少踩我踩过的坑。