如果你已经跟着这个系列一路读到第四篇,估计已经受够了把时间花在“调包、传参、看着输出发呆”上。好消息是,从这一篇开始,你会真正体会到机器学习最直观、最有成就感的部分:让机器从数据里学会一套规则,然后拿去预测它从没见过的新样本。这篇博客讲的是 sklearn 中的分类算法,也是 Python 机器学习系列里动手味道最浓的一篇。我会从分类问题的底层逻辑讲起,一路手把手带你把完整流水线跑通,再用专门的篇幅重点交代那些容易翻车的细节,尤其是评估指标,以及那些会让模型看起来“效果很好”、实际上经不起推敲的隐藏错误。
如果你是刚看完前三篇、对 NumPy 和 Pandas 还不太熟的新手,完全不用慌,本文默认只要求你懂 Python 基础语法,所有算法原理我都会用大白话拆开来讲。如果你已经跑过一些模型,那这篇也许能帮你把“为什么这么写”补上,毕竟很多坑只有踩过才知道在哪。
1. 分类问题到底是什么?先把地基打牢
1.1 用三个场景快速理解分类任务
在进入代码之前,先搞清楚我们在解决什么问题。分类任务的本质,是让模型从带标签的历史数据里学到一套判断规则,然后对未知样本输出一个离散的类别标签。注意“离散”这个词,它把分类和回归区分开了:回归预测的是连续数值,比如房价 3.2 万每平;分类输出的是有限个类别,比如“垃圾邮件”或“正常邮件”。
我用三个最常见的场景来具体说明。第一个是垃圾邮件识别:输入是邮件文本,经过向量化变成特征,输出是“垃圾”或“正常”,这是典型的二分类问题。第二个是手写数字识别:输入是 8x8 或 28x28 的像素矩阵,输出是 0 到 9 十个数字,这是多分类问题。第三个是信贷风控:输入是用户的收入、年龄、历史还款记录,输出是“违约”或“不违约”,而且通常正负样本比例失衡,属于不平衡二分类。你会发现,这些场景的共同点都是:有历史结果可学,有明确类别要分,新数据来了自动预测。
在 sklearn 里,数据的形式高度统一:特征矩阵 X 是一个二维数组,每一行是一条样本,每一列是一个特征;标签 y 是一个一维数组,长度和 X 的行数一致。理解了这个形状,后面所有代码都好懂了。
1.2 为什么选择 sklearn 来做分类
Python 里能做分类的工具其实不少,但 sklearn 几乎是所有人绕不开的起点。它的核心设计值得夸一夸:所有分类器共享同一套接口,主要就是 fit 和 predict。fit 是学习,predict 是预测。这意味着你换算法只是换一行代码,其余流程全部复用。
我举个例子你就明白了。假设你花了一个小时把逻辑回归跑通了,现在想试试随机森林,只需要把分类器那一行从 LogisticRegression() 改成 RandomForestClassifier(),后面 fit、predict、评估的代码一行都不用动。这种统一接口带来的试错成本极低,是 sklearn 能成为事实标准的重要原因。
注意:新手最容易犯的错就是拿到模型直接 predict。必须先 fit,再 predict,否则会报“未拟合”之类的错误。sklearn 里所有监督学习算法都是这个节奏,写顺手之后换库都会很适应。
还有一点,sklearn 的文档和生态非常完整,数据预处理、特征选择、模型评估、交叉验证全都在同一个框架里,不用东拼西凑。所以这篇系列文章把 sklearn 作为核心工具,不是为了赶潮流,而是因为它真的是上手最快、最不容易出错的选择。
2. 常用分类算法选型:七种武器怎么挑
2.1 一张表看懂主流分类器
很多新手拿到数据后的第一个问题不是“怎么调参”,而是“我该用哪个模型”。说实话,没有一种分类器能在所有场景下通吃,但我们可以建立一个选型框架。下面是 sklearn 里最常用的七种分类算法对比,你收藏起来的价值可能比看十遍教程都大。
| 算法 | 决策边界 | 训练速度 | 可解释性 | 适用场景 | 关键注意点 |
|---|---|---|---|---|---|
| 逻辑回归 | 线性 | 快 | 高 | 风控、医疗、baseline | 需要标准化,适合线性关系较强的数据 |
| K 近邻 | 非线性 | 快(预测慢) | 中 | 小样本、低维度 | 必须标准化,特征多了会失效 |
| 朴素贝叶斯 | 非线性 | 极快 | 中 | 文本分类、垃圾邮件 | 特征独立性假设,现实往往不满足 |
| 决策树 | 非线性 | 快 | 很高 | 需要解释规则的场景 | 容易过拟合,深度要限制 |
| 支持向量机 | 非线性(核技巧) | 中 | 低 | 中小样本、高维度 | 必须标准化,调参敏感 |
| 随机森林 | 非线性 | 中 | 中(特征重要性) | 表格数据默认首选 | 相对抗过拟合,不用太多调参 |
| 梯度提升树 | 非线性 | 慢 | 低 | 表格数据精度优先 | 调参复杂,容易过拟合,需要小学习率 |
这个表不是让你背下来,而是给你一个初步印象。下面是每种算法的故事。
2.2 逻辑回归不等于“回归”
逻辑回归名字里带“回归”,实际干的是分类的活。它的核心思想是用一条直线(或超平面)把两类样本分开,然后通过 sigmoid 函数把输出压缩到 0 到 1 之间,解释成概率。比如模型输出 0.8,就表示有 80% 的概率属于正类。
它的优点是训练极快,输出结果可以解释为概率,而且系数能直接反映特征的影响方向。在信贷风控这种强监管场景,业务人员问你“为什么拒绝这个客户”,逻辑回归能给出明确回答:因为收入项系数为负,贡献了较大的违约概率。这是很多黑盒模型做不到的。缺点是决策边界是线性的,面对非线性关系时效果会比较差,但就算这样,它也依然是我做任何表格型数据时第一个跑的 baseline 模型。
sklearn 里的关键参数是 C,它是正则化强度的倒数。C 越小,正则化越强,模型越保守,有助于防止过拟合。
2.3 K 近邻:物以类聚的懒办法
K 近邻大概是所有分类算法里最符合直觉的:找离待预测样本最近的 K 个已知样本,投票决定它属于哪一类。你选 K=5,那看最近的 5 个邻居里哪类多,就预测哪类。
它的优点是原理简单、效果在小数据集上不差,而且不需要显式训练,fit 只是把数据存起来。缺点是预测时要计算新样本和所有训练样本的距离,数据一多就非常慢,业界俗称“惰性学习”。另外距离计算对特征尺度极其敏感:年龄这种 0 到 100 的特征和收入这种 0 到 50000 的特征,算欧氏距离时收入完全主导了结果,年龄几乎不起作用。所以用 KNN 之前必须做标准化,这是几乎所有新手都会踩的坑。
关键参数是 n_neighbors,代表邻居数量。K 太小人容易受噪声影响,K 太大又可能把边界磨得太平滑,一般从 3 到 15 之间的奇数开始试。
2.4 朴素贝叶斯:天真但能打
朴素贝叶斯基于贝叶斯定理,做了一个非常强的假设:所有特征在给定类别条件下相互独立。这个假设在现实中基本不成立,比如“包含买”和“包含便宜”两个词在垃圾邮件里明显有关联性。但神奇的是,它依然在文本分类里表现不错,而且训练速度极快,几乎可以用“秒”来形容。
sklearn 里根据特征分布提供了三种变体:高斯朴素贝叶斯适合连续数值特征;多项式朴素贝叶斯适合离散计数,比如词频;伯努利朴素贝叶斯适合 0/1 形式的特征。我做垃圾邮件过滤实验时,效果最好的往往是多项式或伯努利版本,因为它们处理的正是“词出现与否”这类二值特征。
它的使用门槛极低,无需标准化,对小样本也友好。缺点是概率估计会受独立假设影响,特征之间相关性太强时输出概率会失真,但用来做分类标签通常还是没问题的。
2.5 决策树:一堆 if-else 的自动生成器
决策树本质上是在自动生成一套 if-else 规则。比如判断一个用户会不会流失,第一层可能问“最近一个月登录次数是否大于 3”,第二层再问“是否使用过优惠券”,层层分裂,最后落在叶子节点上的多数类就是预测结果。
它的最大优势是可解释性极高,规则可以直接展示成一棵树,你可以拿给业务方看。而且它不需要特征标准化,因为分裂只看大小比较,尺度不影响。缺点是单棵决策树非常容易过拟合,只要深度够深,它可以把训练集每个样本都记下来,树越深,叶子越纯,但换一批数据效果就崩了。所以 sklearn 里限制过拟合主要靠三件套:max_depth 限制最大深度、min_samples_split 限制分裂所需最少样本数、min_samples_leaf 限制叶子最少样本数。
别一上来就用默认参数跑一棵树然后说它效果差,你需要调一调深度。我的经验是 max_depth 从 3 开始往上试,很多表格场景在 5 到 10 之间就能取得不错效果。
2.6 支持向量机:找一条最宽的马路
支持向量机的思路可以理解为:在两类样本之间找一条“最宽”的分隔线,而且只由离分隔线最近的那几个样本决定,这些样本叫做支持向量。优点是在中小样本、高维度数据上表现很好,配合核技巧还能处理非线性边界,一度是机器学习界的大明星。
但它的缺点也很明显:对特征尺度极其敏感,必须先标准化,否则寻找最优超平面的过程会被大尺度特征带偏;对参数也比较敏感,C 和 gamma 需要调。另外随着样本量增大,训练时间增长得很明显,我试过在几十万条样本上跑 SVM,那个等待过程让人怀疑人生。所以现在的实践中,中小数据集可以考虑 SVM,大样本场景直接考虑树模型或者线性模型更务实。
2.7 随机森林:一群树投票就不慌
随机森林解决的是单棵决策树过拟合的问题,思路是训练很多棵树,然后让它们投票。每棵树只看到一部分样本、一部分特征来训练,这样每棵树都“偏差”一点,但它们投票出来的整体结果方差很小、稳定性很高。
这是我个人最推荐新手优先尝试的模型之一,因为它真的很省心。n_estimators 决定树的数量,默认 100 通常够用;max_features 限制每棵树考虑的特征数,调这个比调深度更有效。它还能输出特征重要性,帮你判断哪些特征在起作用。几乎不需要标准化,对异常值也不敏感,在大多数表格型分类问题上都有不错表现。缺点是模型大、预测速度偏慢、可解释性差一些,另外容易在特征高度稀疏时表现不佳。
2.8 梯度提升树:表格数据的精度天花板
梯度提升树跟随机森林不一样,它不是让树们各自独立投票,而是每一棵新树都去拟合前面所有树的误差,逐步减少残差。这种串行思路让它在表格型数据上精度上限很高,Kaggle 表格赛里几乎看不到随机森林夺冠,但梯度提升类模型出场率极高。
sklearn 里对应的基础版本是 GradientBoostingClassifier,另外还有更快的 HistGradientBoostingClassifier,速度和精度更均衡。关键参数是 n_estimators、learning_rate 和 max_depth。学习率越小,每棵树贡献越小,需要更多树来补齐精度,但泛化往往更好;深度通常保持 3 到 5 就够了,太深的树会让提升过程变得容易过拟合。工业界很多场景用的是第三方梯度提升框架,原理完全相同,学会了 sklearn 版本再转过去非常快。
< 我的建议是:如果你不赶时间,把所有模型都跑一遍交叉验证,对比完再选。迁移成本几乎为零,但收益是你能直观地感受不同算法的差异,这个经验比你背十遍选型手册都管用。
3. 一套完整的分类实操流水线:从数据到评估
3.1 先加载数据并观察类别分布
理论说了不少,现在上真家伙。这一节我用 sklearn 自带的乳腺癌数据集来做演示,它是二分类,标签是良性和恶性,正好能讲清楚精确率和召回率这些关键指标。数据集不用额外下载,对零基础的人非常友好。
先写加载和基本观察的代码:
from sklearn.datasets import load_breast_cancer data = load_breast_cancer() X = data.data y = data.target print('特征矩阵形状:', X.shape) print('标签类别:', data.target_names) print('类别分布:', np.bincount(y))运行后你会看到特征矩阵是 (569, 30),表示 569 条样本、30 个特征;标签类别是 ['malignant' 'benign'],良性样本多、恶性样本略少。为什么要先看类别分布?因为它直接决定后面评估指标怎么选。如果某个类别占比只有 10%,那你用准确率评价模型毫无意义,到第 4 节我会详细展开。
3.2 划分训练集和测试集:这一步影响你后面所有结论
模型不能拿所有数据又训练又评估,否则它只是把题目答案背下来了,考试还是不会。所以要让一部分数据“隐去答案”,让模型学完再去做题。train_test_split 就是干这个的。
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, stratify=y, random_state=42 )这里有两个参数值得单独拎出来讲。第一个是 test_size=0.2,表示 20% 的数据留作测试集,这个比例可以根据样本量调整:样本多可以留 30%,样本少建议只留 10% 到 20%,保证训练数据足够。第二个是 stratify=y,它的作用是保证划分后训练集和测试集的类别比例和原始数据一致。如果你的数据是 90% 良性、10% 恶性,不设置 stratify,可能出现训练集全是良性、测试集全是恶性的极端情况,模型直接报废。所以做分类任务时,我强烈建议每次都用 stratify。
random_state 也建议固定,否则每次划分都会变,模型结果不可复现。你可能会问固定成几最吉利?没有讲究,只要是整数就行,关键是能复现。
3.3 特征标准化:必须用训练集去 fit
很多分类算法对特征的尺度敏感,尤其是逻辑回归、KNN、SVM 这类基于距离或梯度的模型。比如肿瘤尺寸单位是厘米,均值 2,另一个特征比如细胞核面积,可能范围是几百到几千,数值大的特征会在模型里获得不成比例的影响力。标准化的作用,是把每个特征变成均值为 0、标准差为 1 的分布。
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)注意这里第 4 行用的是 transform,不是 fit_transform。这是几乎所有入门教程都会提、但依然有很多人犯的错误。StandardScaler 通过学习训练集数据算出每个特征的均值和标准差,测试集必须沿用训练集的这两个统计量去转换,不能自己重新算。
重要提醒:千万不要对整个 X 做 fit_transform,然后再划分数据集。这会让测试集的统计信息在训练阶段就泄露给模型,属于典型的数据泄漏。测试集必须当“从来没见过的考试题”对待。
3.4 模型训练与预测:fit、predict、predict_proba
数据准备好了,选个模型开始干活。我用逻辑回归做示例,因为它的预测结果可以输出概率,方便后面讲评估指标。
from sklearn.linear_model import LogisticRegression model = LogisticRegression(random_state=42) model.fit(X_train_scaled, y_train) y_pred = model.predict(X_test_scaled) y_prob = model.predict_proba(X_test_scaled) print('前5个预测结果:', y_pred[:5]) print('前5个概率分布:', y_prob[:5])predict 返回的是类别标签,比如 [0 1 0 0 1];predict_proba 返回的是一个二维数组,每一行是这条样本属于每个类别的概率,两个类别加起来等于 1。这两者的关系是:predict 本质上是在概率上做一个阈值判断,二分类默认把概率大于 0.5 的归为正类。
有一个高频翻车点必须先说:predict_proba 返回的列顺序,正类是第 1 列而不是第 0 列,第 0 列对应的是负类的概率。如果你后面要做自定义阈值,比如“只有概率高于 0.7 才判为正”,取正类概率要写 y_prob[:, 1]。这个问题我在实际项目里见过不止一次,取错列之后整个评估结果反向,模型看起来“一塌糊涂”或者“好得离谱”。
3.5 用 Pipeline 把流程串起来,避免重复劳动
上面我们手动做了标准化、训练、预测三步。步骤多了以后很容易忘记用训练集 fit 测试集,或者网格搜索时顺序乱掉。sklearn 提供的 Pipeline 可以把标准化和分类器打包成一个整体:
from sklearn.pipeline import Pipeline from sklearn.svm import SVC pipe = Pipeline([ ('scaler', StandardScaler()), ('clf', SVC(random_state=42)) ]) pipe.fit(X_train, y_train) y_pred = pipe.predict(X_test)这样做的价值马上就能看到:你不需要再手动算 X_train_scaled 和 X_test_scaled,Pipeline 会在 fit 时自动对训练集做标准化,在 predict 时自动用训练集的统计量去转换测试集。后面我们做交叉验证或网格搜索时,这一步能省很多心思,也不容易出数据泄漏的错。
4. 评估指标:准确率之外的那些“数学真相”
4.1 混淆矩阵:把错误拆成四种
我见过太多新手跑完模型,只看一眼 accuracy 就说“效果不错”。这在类别均衡的数据集上问题不大,但一旦类别不平衡,准确率就会骗人。所以我们从混淆矩阵开始,建立一套更完整的评估视角。
混淆矩阵是一个 2x2 的表格,把预测结果和真实结果交叉分组:真正例 TP、假正例 FP、真负例 TN、假负例 FN。看这四个数字的口诀很简单:预测对了,要么是 TP 要么是 TN,取决于真实是正还是负;预测错了,要么是 FP 要么是 FN,也取决于真实标签。
拿乳腺癌场景来说,把恶性判成良性是 FN,漏诊最要命;把良性判成恶性是 FP,虽然虚惊一场,但至少还会做进一步检查,代价相对低。这两个错误对业务的影响完全不一样,所以不能只看总体的准确率。
4.2 精确率、召回率和 F1:什么时候看哪个
精确率 Precision 回答的问题是:你预测为恶性的那些人里,有多少真的是恶性。它关注的是“宁缺毋滥”,避免误报。召回率 Recall 回答的问题是:真实恶性的人里,有多少被你找出来了。它关注的是“一个都不能少”,避免漏诊。两者天然存在矛盾,提高召回率往往会降低精确率,因为你把更多样本判为正类,自然会混入更多误报。
F1 分数是精确率和召回率的调和平均,它试图在两者之间取一个平衡。调和平均对极端值惩罚很重,所以如果精确率很高但召回率极低,F1 会把这种假象拉回去。
到底该关注哪个,取决于业务场景。在商品推荐场景,推荐错了用户顶多不看,但推荐多了没有太大损失,所以可以更看重召回率;在信贷风控场景,把坏客户放进来会造成资金损失,但好客户被拒也只是少挣钱,所以更看重精确率或自定义的风险阈值。每当你听到“这个模型准确率 99%”这种话,先别激动,问一句:你的样本里正负比例是多少?
4.3 ROC 曲线和 AUC:衡量模型排名的能力
ROC 曲线是另一个必须掌握的评估工具,它画的是不同阈值下真正例率 TPR 和假正例率 FPR 的变化。AUC 是曲线下的面积,它衡量的是模型对正负样本排序的能力:随机挑选一个正样本和一个负样本,模型给正样本打出更高概率的可能性有多大。
为什么 AUC 对不平衡数据更稳健?因为它不依赖具体的分类阈值,只看概率排序。就算样本是 99 比 1,只要正样本的概率普遍更高,AUC 依然能反映模型的区分能力。
在 sklearn 里的用法也很简单:
from sklearn.metrics import roc_curve, roc_auc_score fpr, tpr, thresholds = roc_curve(y_test, y_prob[:, 1]) auc = roc_auc_score(y_test, y_prob[:, 1]) print('AUC:', auc)需要说明的是,AUC 也并非万能。在类别极度不平衡时,AUC 会偏高,因为它对大量负样本的分类表现不够敏感。实操里我通常把混淆矩阵、F1、AUC 三者放一起看,才能拼出模型的全貌。
5. 常见问题与排查实录:这些坑我替你踩过了
5.1 数据泄漏:测试集信息偷偷溜进训练集
这是最常见也最隐蔽的问题。除了前面说的标准化必须在训练集上 fit 之外,缺失值填充、特征选择、异常值处理都可能犯同样的错误。比如你先把全量数据的均值算出来,填进缺失值,然后再划分训练测试集,那么这个均值就包含了测试集的信息,测试集就不再是“未知”的了。正确做法是只对训练集计算填充值,测试集用它来填。判断数据泄漏的一个简单信号是:交叉验证结果远低于单次划分结果,或者测试集分数高得离谱,这个时候先回头检查预处理流程。
5.2 类别不平衡:模型直接躺平了
如果正类占比不到 10%,很多模型会直接学会“全都预测成负类”,这样总体准确率也有 90% 以上,但实际一个正类都没抓住。解决办法从几个层面下手:数据层面可以尝试过采样或欠采样,让类别比例更均衡;算法层面,sklearn 里很多分类器支持 class_weight='balanced',它会自动给少数类更高的惩罚权重;评估层面,放弃准确率,改用召回率、F1、AUC。我做过一个违约预测项目,正类只有 3%,调整 class_weight 之后召回率从 0 提升到了 60% 以上,代价是精确率掉了不少,但业务上能接受了。
5.3 过拟合:训练集满分,测试集不及格
过拟合的本质是模型把训练数据里的噪声也记住了。树模型最容易这样,因为深到一定程度叶子节点非常纯,每个训练样本都有自己的“专座”。对策也直接:降低模型复杂度,比如限制树的 max_depth、提高 min_samples_split、给逻辑回归加正则化;或者增加训练数据量,让模型看到更多样化的样本;再用交叉验证确认模型在不同数据子集上的表现。最关键的判断标准是训练集和验证集的分数之差,差距大就要警惕。
5.4 predict_proba 的列顺序搞反了
这个坑我在 3.4 已经提过一次,但值得放进问题清单,因为它太容易发生。二分类的 predict_proba 输出两列,第 0 列是负类概率,第 1 列是正类概率。如果你用自定义阈值,务必先确认 classes_ 的顺序:
print(model.classes_)大多数情况下它按标签从小到大排列,所以 classes_[0] 是负类,classes_[1] 是正类。遇到标签不是 0 和 1 的数据集时,不要靠猜,直接打印 classes_ 看顺序。
5.5 随机种子不固定导致结果无法复现
你会发现同样的代码跑两次,结果数字有时候差一点,这不一定是你写错了,而是随机性在作祟:train_test_split 的切分、随机森林的样本抽样、SVM 优化过程中的初始化都可能引入随机性。解决办法是给关键函数都设 random_state,统一一个固定值。这不仅是强迫症,而是为了可复现,方便对比不同模型的真实差异。如果某个模型设定 random_state 后结果还有轻微波动,基本就可以判断是并行计算或底层库导致的。
5.6 特征尺度不统一拖垮距离类模型
KNN、SVM、逻辑回归这些模型在特征尺度差异大时都会受到严重影响。可以用一个小例子来理解:假设两个人年龄差 1 岁,欧氏距离是 1;收入差 1000 元,欧氏距离是 1000。那么在距离计算里年龄基本被忽略了。解决办法就是标准化或归一化。值得注意的是,决策树和随机森林不受影响,它们基于分裂点做判断,不做距离计算,所以对要不要标准化的争论,核心在于你用了什么模型。
5.7 GridSearchCV 跑得太慢怎么办
网格搜索是调参利器,但它本质上是“暴力枚举”,参数多、数据量大时非常磨人。我自己的习惯是:先用比较少的数据量或粗粒度的参数网格跑一遍,确定大致方向,再用细粒度微调。另外,RandomizedSearchCV 通常比 GridSearchCV 更实用,尤其是参数维度多的时候,它会在指定分布里随机采样组合,不需要枚举全部。还有一个小提醒:记得设 n_jobs=-1,让 Sklearn 用多核并行,速度提升立竿见影;verbose=1 也能让你看到搜索进度,不用干等。
5.8 特征工程和调参,哪个更重要
最后一坑算不上“报错”,而是方向性问题:新手往往花大量时间调参,却忽视特征本身的质量。我做过的多个项目中,一次有价值的特征工程带来的提升,往往比调参大得多。比如把时间戳拆成“是否工作日”“是否节假日”,把连续变量做分箱,给文本做 TF-IDF 向量化。模型会把好特征变成好结果,但好参数不会把垃圾特征变成好模型。所以调参之前,先问问自己:我已经把数据里的信息榨干了吗?
6. 后续如何进一步扩展
分类算法这篇写完之后,整个系列可以往几个方向深入。最自然的下一步是模型调优与交叉验证:你可以用交叉验证全面评估模型稳定性,用网格搜索寻找最优参数。这里要提醒的是,网格搜索和交叉验证跟 Pipeline 搭配使用效果最佳,因为预处理步骤也会被纳入交叉验证的每一折,避免数据泄漏。我在实际项目里会建立一套标配:Pipeline 包特征处理、模型对象,GridSearchCV 调参,最后再用测试集做终评。
再往深走,可以关注特征工程与特征选择。分类问题的上限往往不只在模型,更在特征。手动构造的交叉特征、分箱特征、目标编码,都可能让 F1 上一个台阶。sklearn 里的 SelectFromModel、RFECV 都是实用工具,能帮你筛选出真正有解释力的特征。
如果想把模型推到生产环境,还要关心模型保存与加载,用 joblib 或 pickle 把训练好的模型文件持久化,再用脚本加载并批量预测。这是“能运行”迈向“能上线”的关键一步。
我个人在这几轮实战中最大的体会是:不要迷信任何一个算法。逻辑回归简单,但可解释性和稳定性极高;随机森林省心,但精度上限摆在那里;梯度提升强,但调参成本和过拟合风险都不低。你能做的是把流水线搭稳,把评估指标吃透,然后让数据说话。这篇文章里的代码你完全可以照着跑一遍,再换成自己的数据试试。分类模型从来不是哪个算法最厉害,而是在理解业务和数据之后,选出那个在精准与稳妥之间最平衡的选择。