1. 为什么记录这份分类器笔记
最近把机器学习的基础笔记重新过了一遍,写到分类器这一章的时候发现内容比想象中多得多。当初学的时候很多概念是散的,比如逻辑回归、决策树、SVM 各学各的,背完公式就忘;等真正拿一份数据去分类,才发现核心问题根本不是“哪个模型最好”,而是“这个场景该用哪种模型的什么版本、配什么参数、怎么看效果”。这份第三篇笔记,就是把“分类器”从原理到实操的完整链路重新整理了一遍。
分类器是监督学习的核心,它的任务是学会从特征到离散标签的映射。不管是垃圾邮件识别、用户流失预测、图像类别判断,还是工业缺陷检测,本质都在做同一件事:给定一组特征 x,预测它属于哪个类别 y。很多人会把分类和回归搞混,其实一句话就能说明白:回归输出连续数值,比如房价 300 万;分类输出离散标签,比如“会流失”和“不会流失”。分类又分二分类、多分类、多标签,最常见的是二分类,很多多分类问题本质也能拆成多个二分类来解。
这份笔记适合两类人看:一是刚学完回归、准备进入分类阶段的初学者,二是学了一轮理论但动手做项目时总卡壳的实践者。我不会按教材的章节顺序把每个算法从头到尾推一遍公式,而是按“遇到问题怎么选模型、怎么处理数据、怎么评估结果”的实操线索来组织。你把它当成一份分类器速查手册,比直接翻教材舒服得多。
2. 核心细节解析:八种常用分类器的原理画像
2.1 逻辑回归——最像“回归”的分类器
逻辑回归虽然名字里带“回归”,但它是一个典型的分类器。它的思路很直白:先用线性模型算出一个实数分数 z = w·x + b,然后通过 Sigmoid 函数把它压缩到 0 到 1 之间,理解为正类的概率。如果概率大于 0.5,就判成正类,否则判成负类。
这个模型的好处第一是可解释性极强。每一个特征的权重 w 直接告诉我们,该特征每增加一个单位,正类概率的对数几率变化多少。业务人员完全能看懂。第二是训练速度极快,内存占用也小,在高维稀疏场景里表现特别稳定。我实际做过一个基于用户行为特征的分类项目,特征经过 One-Hot 之后维度超过 10 万,逻辑回归配合 L1 正则化不但能收敛,还会自动把不重要的特征权重压成 0,相当于内置了特征选择。
实操里有几个值得注意的细节。特征标准化对逻辑回归的收敛速度影响很大,尤其用梯度下降训练时,不归一化会导致某些维度更新过慢或振荡。还有一个容易被忽略的点:逻辑回归输出的概率并不是“真实的概率”,它是模型对置信度的一种度量,阈值不是固定的 0.5。如果你更看重召回率,可以把阈值下调到 0.3;更看重精确率就上调到 0.7。很多初学者不知道这个操作,白白浪费了一个调节手段。
2.2 决策树与随机森林——有据可查的分叉路
决策树的原理像小时候玩的“二十个问题”游戏:每次问一个最能区分样本的问题,把数据分成两个子集,然后在子集里继续问,直到子集足够“纯”。这里的纯度用信息增益或基尼系数来衡量,选特征的标准就是“哪个特征让分裂后的数据更纯”。
决策树最大的优势是可视化之后非常直观,非技术背景的人也能看懂规则。比如银行判断是否放贷,树的分支可能是“月收入大于 8000 → 婚姻状况已婚 → 放贷”。这种可解释性在合规要求严格的场景里价值极高。
但单棵决策树的敌人是过拟合。一棵树如果长得太深,会把训练样本的个人特征当普遍规律,测试集一验证就翻车。解决办法是砍掉深度、设置最小叶子样本数,或者改用集成方法。随机森林就是众多决策树投票的结果,它干了两件事:首先对训练数据做有放回的抽样(Bootstrap),每棵树用不同的样本子集;其次在每个节点分裂时随机选一部分特征做候选。这样得到的树各有侧重,平均投票之后方差大幅降低,过拟合的风险比单棵树小得多。
实操中我习惯把随机森林当成表格数据的第一个 baseline,因为它对特征尺度不敏感、处理非线性关系也够用,几乎不用做太多预处理就能跑出一个不错的精度。然后看它给出的特征重要性,作为后续特征工程的参考依据,再决定要不要换更强的模型。
2.3 SVM——用超平面切数据
SVM 的全称是支持向量机,核心思想是找到一个超平面,让两类样本之间的间隔最大化。间隔越大,分类的泛化能力往往越好,因为决策边界对样本的轻微扰动不敏感。在二维空间里这个超平面就是一条线,三维里是一个面,高维里就是抽象的超平面。
真正让 SVM 强大的是核技巧。现实数据很多时候线性不可分,比如一类样本包围着另一类。此时可以把原始特征映射到高维空间,在新的空间里找一个能分开的超平面。核函数的作用是隐式计算高维空间的内积,不用真的把数据映射过去。最常见的 RBF 核,相当于把样本映射到无穷维空间,配合合理的参数,几乎能拟合任意复杂的分类边界。
但 SVM 有两个明显的短板。一是训练复杂度随样本量增长很快,几万条数据还能接受,到了几十万条就很痛苦。二是它对特征尺度敏感,因为决策边界依赖样本与超平面的距离,如果某个特征的数值范围远大于其他特征,距离计算会被这个特征主导,所以用 SVM 之前必须做标准化。参数方面,C 控制误分类惩罚力度,C 越大越追求训练集上全对,容易过拟合;gamma 控制 RBF 核的影响半径,gamma 越大,决策边界越弯曲,同样容易过拟合。调参时我一般先用 C=1、gamma=0.1 起步,画出边界观察,再逐步排查。
2.4 KNN 与朴素贝叶斯——两个极端流派
KNN(K 最近邻)和朴素贝叶斯风格完全不同,一个是“对比派”,一个是“概率派”。
KNN 不训练模型,它只是把训练数据存下来,预测新样本时就找距离最近的 K 个已知样本,投票决定类别。好处是可以处理复杂的非线性边界,而且理论上没有训练过程,加新数据很灵活。但是预测阶段的代价很高,每条新样本都要和所有训练样本算距离。如果训练集有几百万条,线上预测会慢得让你怀疑人生。还有一个致命问题,就是维度灾难:当特征维度很高时,样本间的距离趋于平均,最近邻的概念变得不再可靠。
朴素贝叶斯走的是另一路线。它用贝叶斯定理计算“给定特征下属于每个类别的概率”,然后选概率最大的类别作为预测。它的“朴素”体现在一个强假设上:所有特征在给定类别下相互独立。这个假设在现实中往往不成立,但神奇的是它在大量实际任务中依然好用,尤其适合文本分类。比如垃圾邮件识别,可以把一封邮件拆成一组词,每个词看作一个特征,假设词在垃圾邮件和正常邮件里独立出现,计算邮件属于两类各自的概率。训练过程几乎是一遍扫描统计词频,又简单又高效。
两个模型选哪个,核心看数据规模和特征结构。小规模低维数据、边界复杂非线性,优先试 KNN;高维稀疏数据、文本特征,朴素贝叶斯几乎总是更靠谱。
2.5 GBDT 系——表格数据的常胜将军
这几年做表格数据竞赛的人,几乎绕不开 GBDT 系模型。GBDT 是梯度提升决策树的缩写,思路是串行地训练多棵树,后一棵树专门学习前面所有树的残差。每棵新树都在修正整体预测的误差方向,累积起来就能得到很强的拟合能力。常用的工程实现有 XGBoost、LightGBM 和 CatBoost,虽然底层细节不同,核心思想是一脉相承的。
为什么 GBDT 在表格数据上几乎碾压深度学习模型?因为表格数据的特征通常是异构的,有连续值、有离散类别、有缺失值,深度学习需要大量特征工程才能处理,而梯度提升树天然支持分裂点的搜索,能自动捕捉特征之间的非线性交互关系,还可以直接处理缺失值。它的训练效率也被不断优化,LightGBM 使用直方图算法和叶子生长策略,几千条样本和几十万条样本的体验差距并不像想象中那么大。
在实战中,我习惯这样安排:先用随机森林作为快速 baseline,然后切换到 LightGBM 取得更高精度,如果追求极致精度再叠加 XGBoost 做融合。这里要说一下随机森林和 GBDT 的本质区别:随机森林是 Bagging 方式,并行建树、结果平均,目标是降低方差;GBDT 是 Boosting 方式,串行建树、不断纠错,目标是降低偏差。随机森林更稳,不容易过拟合,但上限往往低于 GBDT;GBDT 的上限高,却更容易在参数不合适时过拟合。调 GBDT 时,宁肯把学习率设小一点、树的数量设多一点,配合早停,也别一上来就把树加深加高。
| 模型 | 核心思想 | 优点 | 主要坑点 | 典型场景 |
|---|---|---|---|---|
| 逻辑回归 | Sigmoid 映射线性分数 | 可解释、训练快、适合高维稀疏 | 特征标准化、非线性弱 | 风控、点击率预测 |
| 决策树 | 递归分裂提升纯度 | 可解释性最好 | 易过拟合、不稳定 | 规则提取 |
| 随机森林 | Bagging + 随机特征 | 稳、适合当 baseline | 对高维稀疏表现一般 | 表格数据初版 |
| SVM | 最大间隔超平面 + 核函数 | 小样本高维效果好 | 训练慢、必须标准化 | 图像小样本、文本 |
| KNN | 距离投票 | 简单、无训练过程 | 大样本预测慢、维度灾难 | 小规模数据 |
| 朴素贝叶斯 | 条件独立假设 + 贝叶斯公式 | 训练快、适合文本 | 独立性假设通常不成立 | 垃圾邮件、情感分类 |
| GBDT 系 | 串行拟合残差 | 表格数据精度上限高 | 调参复杂、易过拟合 | 竞赛、工业表格任务 |
3. 实操过程与核心环节实现
3.1 数据从哪里来,先处理什么
分类器不是拿来数据就能直接跑。我通常拿到一份新数据,前 40% 的时间都花在数据清洗和特征工程上,后 60% 才是建模调参。这是很多人容易颠倒的主次关系。
先说缺失值。很多人对缺失值直接填均值,这是偷懒。更好的做法是先问一句“数据为什么缺失”:如果缺失本身包含信息,就造一个“是否缺失”的特征给模型;如果是随机缺失,再考虑均值、中位数、众数填充。类别变量的缺失,我习惯单独填一个“unknown”类别,让树模型自己决定怎么分裂。
再说类别编码。常见误区是把类别直接映射成 0、1、2 这样的整数。如果这个类别是名义变量,比如颜色、城市,这种编码等于强行给类别排了序,模型会学到“城市 2 比城市 1 大”的错误关系。正确处理是用 One-Hot 编码,或者用目标编码、频率编码这类更高级的做法。示例很简单:
import pandas as pd df = pd.DataFrame({'city': ['北京', '上海', '广州', '北京']}) # 错误的做法 df['city_code'] = df['city'].astype('category').cat.codes # 正确做法 df_encoded = pd.get_dummies(df, columns=['city'])值得注意的是,如果类别取值很多,比如 IP 地址或 ID 列,One-Hot 会导致维度爆炸,这时候可以统计每个类别的目标均值做目标编码,或者直接不编码让树模型当序号用——树模型不受这种顺序编码的影响,但线性模型和 KNN 必须谨慎处理。
3.2 训练集和测试集怎么分
分类器训练的第一步是划分数据,但很多人真的就是随机一 split,埋了雷还不自知。核心原则是:划分后训练集和测试集的类别分布要尽量一致。可以用分层抽样来实现,Python 里只需要一行参数:
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y # 按类别比例分层 )如果不加 stratify,当类别不平衡时,很可能测试集里某个类别的样本太少甚至消失,模型评估结果随之失真。
时间序列数据就要更慎重,随机切分等于让模型“偷看未来”。比如用过去 30 天的数据预测今天是否发生某事件,必须按时间先后划分:前 80% 做训练,后 20% 做测试,甚至用滚动窗口的方式做多轮验证。
3.3 模型评估指标怎么选
准确率是最直观的指标,也是最大的坑。我见过一个极端案例:某风控项目正样本只占 1%,模型把所有样本都判为负类,准确率高达 99%,看起来完美,但实际业务意义为零,因为一个高风险用户都没抓住。
真正要关心的,是混淆矩阵里四个格子之间的关系。精确率衡量“模型说正类的样本里,真的正类占多少”,召回率衡量“真正的正类样本里,模型抓到了多少”。这两个指标经常此消彼长,F1 是它们的调和平均。AUC 衡量模型对样本排序的能力,对阈值不敏感,适合比较模型整体好坏,但不容易直接对应业务收益。
不同场景的指标选择完全不同。欺诈检测更看重召回率,因为漏掉一笔欺诈的代价远大于多调查几笔正常交易;商品推荐则更关心精确率,因为推荐没兴趣的商品给用户会直接伤害体验。做分类器评估前,先想清楚假阳性和假阴性各自的代价,再选指标。我给初学者一个标准做法:如果不知道业务细节,至少把混淆矩阵打印出来,看一眼四个数值,别只看一个准确率。
3.4 一个完整的分类实验脚本参考
学习阶段不用动手写太复杂的框架,但要养成用 Pipeline 的好习惯。Pipeline 最大的价值是防止数据泄漏:如果先对全量数据做过标准化再划分训练测试集,标准化器就已经“看过”测试集的分布,会让评估分数虚高。正确做法是把预处理放在 Pipeline 里,让它只对训练集 fit,再 transform 测试集。
下面是一个用逻辑回归做分类的参考骨架,代码清晰到可以直接套用到绝大多数表格分类任务:
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score pipe = Pipeline(steps=[ ('scaler', StandardScaler()), ('clf', LogisticRegression(C=1.0, max_iter=1000)) ]) # 交叉验证评估 scores = cross_val_score(pipe, X_train, y_train, cv=5, scoring='f1') print(f'CV F1: {scores.mean():.4f} ± {scores.std():.4f}') # 全量训练并预测测试集 pipe.fit(X_train, y_train) y_pred = pipe.predict(X_test)用交叉验证而不是单次划分,是因为单次划分的结果受随机性影响太大,一次高一次低,根本没法判断一组参数是好是坏。五折交叉验证取均值,至少能从统计上更可靠地比较不同模型。
4. 常见问题与排查技巧实录
4.1 类别不平衡怎么处理
类别不平衡是分类实战里最常遇到的问题之一。正样本占比可能只有 5% 甚至 0.1%,直接训练的话模型会学会“全部判断为负类”这种偷懒策略。
处理思路有三条。第一是重采样:过采样让少数类样本重复出现,欠采样丢掉大量多数类样本。第二是算法层面:逻辑回归和 SVM 里有 class_weight 参数,可以给少数类更高的误分类惩罚;树模型里也有类似机制,例如 LightGBM 的 scale_pos_weight。第三是评估层面:不要只看准确率,改用 PR 曲线或 F1 作为核心指标。
我的经验是,先别急着上复杂的 SMOTE 过采样,先用 class_weight 这种最朴素的手段跑一版,看指标提升多少再决定后续。过采样最容易被忽略的坑是:如果先过采样再划分训练集和测试集,少数类样本会同时出现在两边,导致评估结果虚高。正确做法是先划分,只在训练集内部做重采样。
4.2 过拟合的典型信号与对策
过拟合的典型信号特别容易识别:训练集上 F1 是 0.98,测试集只有 0.72,差距大得离谱,或者训练损失一路下降、验证损失先降后升。出现这种情况,说明模型把训练数据里的噪声也背下来了。
针对不同分类器,对策要有侧重。决策树类模型,直接限制树深度和叶子节点最小样本数;线性模型,加大正则化强度;GBDT,把学习率调低、树的数量调高,然后使用早停,让模型在验证集指标不再提升时立刻停止训练。还有非常重要的一步:画出学习曲线。横轴是训练数据量,纵轴是得分,观察两条曲线的收敛趋势,能帮你判断是欠拟合、过拟合还是单纯数据不够。
注意,交叉验证看起来能缓解过拟合问题,但它只能帮你发现过拟合,不能消灭过拟合。判断“这个模型能不能用”,最终还是要看留出测试集的表现。
4.3 特征尺度为什么重要
这个问题我反复踩坑,因为不同模型的“世界观”完全不一样。KNN 靠距离判断“谁离得近”,SVM 靠距离找最大间隔超平面,逻辑回归靠梯度下降更新权重。这些模型对特征数值的绝对大小极其敏感。假如一个特征范围是 0 到 1,另一个是 0 到 1 万,距离计算基本由第二个特征一票决定,第一个特征说了等于白说。
树模型就没有这个烦恼,因为决策树只在单个特征上做阈值比较,无论特征范围是 0.001 还是 10000,都能找到合适的分裂点。所以我在做随机森林或 GBDT 时经常跳过标准化,但一旦换成 SVM 或 KNN,标准化就是第一道工序。
标准化和归一化也要分清:StandardScaler 把均值变为 0、标准差变为 1,适合大多数情况;MinMaxScaler 把数值压到 0 和 1 之间,适合有明显上下界的数据。还要记住一点:标准化器必须只在训练集上 fit,再作用到测试集上,否则也属于数据泄漏。
4.4 从“能跑”到“好用”的调参思路
很多新手一上来就对所有参数做 GridSearchCV,参数组合指数量级爆炸,跑了一晚上也没出结果。调参不是碰运气,而是有节奏的排查过程。
我的习惯是“先粗后细,固定再搜”。拿 SVM 举例,先把 C 固定在 1,扫一遍 gamma 的对数范围搞清楚数量级走向,然后固定 gamma,扫 C,最后再在最优值附近做小范围精细搜索。对 GBDT 这类参数更多的模型,调参顺序一般是:先确定树数量,再用早停确定学习率,再调树的深度和叶子节点数,最后微调正则化参数。
聊到搜索工具,GridSearchCV 是网格搜索,优点是不漏解,缺点是完全随机地消耗算力。它默认把所有组合都跑一遍,参数一多就不是“搜索”而是“灾难”。RandomizedSearchCV 在参数空间里随机抽样,跑的次数少得多,常常能用更短的时间找到足够好的参数。再往上还有 Optuna 这类贝叶斯优化工具,它会根据历史搜索记录推断哪些参数区域更有可能出好结果,是更聪明的方向。建议初学者从 RandomizedSearchCV 切入,理解思路后再进阶。
4.5 从模型到项目落地前必做的几件事
如果在本地 notebook 上精确率、召回率都很好看,先别急着说“项目完成了”。落地的路比训练模型更考验工程能力。
第一步要检查线上和线下的数据一致性。训练阶段用的字段,线上是否都有?特征处理用了哪些依赖,比如当前时间或者全局统计量,线上能不能实时算出来?我就遇到过训练时用了整个项目的目标均值作特征,上线后发现这个均值在线上只能靠 T-1 的离线数据算,线上和线下特征定义直接不一致的情况。
第二步要重视模型的解释性需求。业务方会问“为什么把这个人判成正类”,仅靠 GBDT 的黑盒输出很难回答。常见方案是输出 SHAP 值,解释每个特征对预测结果的贡献方向与大小。现在很多工具都提供了可视化,非技术人员也能看得明白。
第三步是监控。模型上线之后,输入分布可能随时间漂移,召回率可能只在训练集上高。建议保留一份部署后的样本,定期重算指标,同时监控特征分布有没有发生显著变化。分类器不是一次训练完就一劳永逸的静态产物,它需要持续维护。
5. 我的个人实操体会
学了这么多分类器,做了几个完整项目之后,我的体会是,模型本身只是拼图的一部分。调试到后来,真正拉开差距的是对数据的理解、对指标的选择,以及对“业务值多少钱”的判断。
比如逻辑回归项目里,我用 SHAP 分析特征后发现,一个被工程团队造出来的“用户活跃天数占比”特征,贡献排在几乎所有原始特征之前,一个强特征顶十个弱特征。这就是特征工程的价值,也是分类器里面最值得你花时间的部分。另外,多个模型效果接近时,尽量选简单且稳定的那个,因为线上维护成本和解释成本往往比精度提高的几个百分点更影响项目成败。
最后分享一个实用的小技巧:给分类器做实验时,写一个统一的评估函数,把混淆矩阵、精确率、召回率、F1、AUC 一次全部打印出来,所有模型都用这个函数评估。这样切换模型时就能快速对比,不用每次都重写一堆评估代码。分类器的学习就是不断重复“设计实验、跑模型、看指标、分析错误、调整方案”这个循环,多跑几轮,手感自然就出来了。