news 2026/10/20 4:10:00

用Scikit-learn实现第一个分类模型:从数据划分到模型评估的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Scikit-learn实现第一个分类模型:从数据划分到模型评估的完整指南

很多人学机器学习,第一件事就是找个教程把代码跑通。但跑通之后呢?模型到底在干什么,数据为什么要这样切分,为什么评估结果要看好几个数字而不是只看准确率,这些往往是模糊的。这篇文章我打算用 Scikit-learn 一步步带你实现第一个分类模型,从数据准备到训练评估,再到你会遇到的典型坑。我不只给代码,更会解释每一步背后的逻辑,让“照着敲”变成“懂了再敲”。

这个内容适合刚接触机器学习、会用一点 Python、但还没有完整做过一个模型的人。如果你已经跑过一些 Demo 但感觉心里没底,这篇也能帮你把流程里的关键环节重新捋一遍。所有案例都是公开数据集,代码可以直接复制运行,不依赖任何外部服务。

1. 第一个分类模型,到底在解决什么问题

1.1 分类问题的本质:给数据贴标签

分类模型解决的是一类非常具体的问题:给定一堆对象的特征,让你判断它属于哪个类别。比如判断一封邮件是正常邮件还是垃圾邮件,判断一张图片里是猫还是狗,判断一个用户明天会不会流失。特征是你观察到的信息,类别是你想预测的结果,模型做的事情就是在特征和类别之间找一个规律。

这个“找规律”的过程,和你平时做判断很相似。你在路上看到一只动物,耳朵尖、体型小、叫声像猫,你会判断它是猫。你用的就是耳型、体型、叫声这几个特征,基于过往经验得出了“猫”的结论。机器学习模型做的事本质上一样,只不过“过往经验”不是人生经验,而是你喂给它的数据。它从大量“特征 + 正确结果”的样本里学习规律,再用学到的规律去预测没见过的新样本。

理解了这一点,你就能明白为什么数据这么重要。模型能学到什么规律,完全取决于你给了它什么数据。如果数据里的特征和标签没有稳定关系,模型再厉害也白搭。这一点在后面的实操中会反复体现。

1.2 为什么选择 Scikit-learn 而不是自己从零写

我第一次想实现一个分类模型时,也动过“自己写梯度下降”的念头,觉得那样才算真正理解。后来发现这是新手最容易走进的死胡同。自己写确实能加深理解,但会陷入大量细节——损失函数怎么求导、学习率怎么调、梯度更新怎么写——这些跟“解决分类问题”本身没什么直接关系。

Scikit-learn 的价值在于,它把机器学习里最常用的算法、数据预处理工具、评估指标都封装成了统一的接口。你想用逻辑回归,两行代码就完成了;你想做特征缩放,有现成的类可以调用;你想评估模型效果,一行代码能算出准确率、精确率、召回率。它不会替你思考,但能把你从重复劳动里解放出来,让你把精力放在数据、特征、模型选择这些真正影响结果的事情上。

另外一个很现实的原因是生态成熟。它和 NumPy、Pandas 配合得很自然,数据格式统一,网上资料也丰富。遇到报错基本都能搜到解决方案,对新手友好得多。

1.3 环境准备:能跑通就是胜利

正式开始之前先搭好环境。我强烈建议用 Anaconda 管理 Python 环境,它能省掉很多不必要的折腾。装好之后创建一个新环境:

conda create -n ml-basic python=3.11 conda activate ml-basic pip install scikit-learn matplotlib pandas

这三个库是你起步阶段全部的家当。scikit-learn 提供模型和评估工具,pandas 负责数据处理,matplotlib 用来画图。装好之后验证一下版本,避免后面因为版本差异出现让人摸不着头脑的报错:

import sklearn print(sklearn.__version__)

只要不报错,环境就准备好了。接下来所有代码都假设你已经在这样的环境里运行。

2. 数据准备:先把手里的牌整理清楚

2.1 用自带的经典数据集,别急着找真实数据

很多新手一上来就去找真实业务数据,但真实数据往往有缺失值、格式混乱、标签不明确,这些问题会严重干扰你学习主线。Scikit-learn 内置了好几个经典数据集,我最推荐拿来做第一个分类模型的是鸢尾花数据集。它包含 150 个样本,特征只有 4 个——花萼长度、花萼宽度、花瓣长度、花瓣宽度,标签是 3 种鸢尾花。数据小、干净、规模适中,是绝佳的起步练习。

加载方式很直接:

from sklearn.datasets import load_iris iris = load_iris() X = iris.data y = iris.target

X 是一个二维数组,每一行是一个样本的 4 个特征值;y 是一维数组,每个值是 0、1、2 之一,分别对应 3 种不同类别。打印一下这两个变量的形状,你会看到 (150, 4) 和 (150,),这是机器学习里最经典的输入格式:样本在最前面,特征在后面。

2.2 特征矩阵和标签向量,为什么是这种格式

在继续之前,我想把 X 和 y 的概念彻底讲透,因为后面所有模型都围绕它们展开。

X 是特征矩阵,每一行代表一个对象,每一列代表一种属性。鸢尾花的 4 列就是花萼长度这些指标。y 是标签向量,它和 X 的行数完全一致,每一行对应一个样本的正确类别。这种格式在整个机器学习生态里是通用标准,无论你用哪种模型、哪个库,几乎都要先把数据整理成这个形状。

新手最容易犯的错误是在脑子里把“特征”和“标签”搞混。你可以这样区分:特征是你观察到的输入,标签是你要预测的输出。一个样本由“特征 + 标签”组成,训练时模型看的是二者的组合。

用 Pandas 看一眼数据会更有直觉:

import pandas as pd df = pd.DataFrame(X, columns=iris.feature_names) df['label'] = y df.head()

看到表格里每一行都同时拥有特征和标签,你对“监督学习”的理解会立刻具象起来——所谓监督,就是有标准答案,模型从标准答案里学规律。

2.3 训练集和测试集的划分,千万别用手里的全部数据去训练

这是整个建模流程里最重要的步骤之一,也是新手最容易忽略的一步。我见过不少朋友用全部数据训练模型,然后拿“准确率 98%”到处说。这个 98% 一点意义都没有,因为模型对训练数据已经过度熟悉了,就像一个学生拿着做过的原题考试,成绩再高也没有参考价值。

划分训练集和测试集的目的,是模拟真实场景:模型只能看到“练习题”,考试时遇到的是“新题”。测试集里的样本在训练阶段完全不可见,这样才能检验模型是否真的学到了可以泛化的规律,而不是死记硬背。

Scikit-learn 提供了一个专门的工具:

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 )

test_size=0.2 表示拿出 20% 的数据做测试。random_state=42 是随机种子,保证每次运行切分结果一样,便于复现。stratify=y 是按标签比例分层采样,保证训练集和测试集里 3 种类别的比例和原始数据一致。如果不分层,一个类型可能全被分到测试集,另一个类型在训练时根本没见过,结果就会严重失真。

注意:随机种子不是可选项,我建议每次划分都固定一个值。它不改变结果质量,但能让你的实验和调试过程可复现,后续调整代码时能清楚地知道“结果变化是因为我改了代码,还是因为重新切分了数据”。

3. 逻辑回归跑通全流程:你其实已经在“学习”了

3.1 为什么第一个模型选逻辑回归

你可能听说过 SVM、随机森林、神经网络这些听起来更高级的名字,但第一个模型我强推逻辑回归。原因很简单:它是线性分类器,原理相对透明,结果容易解释,而且对小数据集来说效果通常不差。先用简单的模型跑通整个流程,建立基线,之后再去尝试复杂模型,这是实践中非常有效的路线。

逻辑回归做的事情可以这样理解:它给每个特征学一组权重,把所有特征加权求和得到一个数值,再把这个数值映射成 0 到 1 之间的概率。概率超过 0.5 就判为正类,低于 0.5 就判为负类。如果你预测的是 3 种鸢尾花,它会在内部训练多个“一对多”分类器,最后综合判断哪个类别概率最高。

权重的大小和正负是有含义的。某个特征的权重为正且绝对值大,说明这个特征越大会让样本更倾向于这个类别;为负则相反。所以逻辑回归的系数天然具有可解释性,这是它作为第一个模型的额外红利——你能看到一个特征具体是怎么影响分类结果的。

3.2 fit 和 predict:Scikit-learn 接口的隐藏逻辑

Scikit-learn 里几乎所有模型都遵循统一接口,核心就四个字:fit 和 predict。fit 是训练,predict 是预测。理解了这两个方法,你基本上就能用所有模型。

fit 的过程就是模型“学习”的过程。以逻辑回归为例,它会在训练集上反复迭代,尝试不同的权重组合,直到找到一组权重使得训练样本的预测结果和真实标签尽量一致。这个过程由算法自动完成,你不用关心梯度怎么算,但要明白它确实是在求解一个优化问题。

predict 则是在训练结束后进行的。模型拿测试集的特征作为输入,根据学到的权重计算出每个样本属于每个类别的概率,然后返回概率最高的那个类别。

完整代码如下:

from sklearn.linear_model import LogisticRegression model = LogisticRegression(max_iter=2000) model.fit(X_train, y_train) predictions = model.predict(X_test) print(predictions)

你运行之后会看到一列数字,那就是模型对测试集每个样本的预测类别。到这里,你的第一个分类模型已经跑通了。从数据处理到模型训练到预测,一条完整的链路已经建立了。

3.3 模型内部到底学到了什么

我习惯在训练完成后打印出模型的权重,这会让你对“模型学了规律”这件事有很直观的感受:

import numpy as np feature_names = iris.feature_names for i in range(3): print(f"类别 {i}:") for name, coef in zip(feature_names, model.coef_[i]): print(f" {name}: {coef:.2f}")

你会看到每个类别对每个特征都有一套自己的权重系数,这正是模型的“经验”。往后遇到新样本,它就按这套系数做计算打分。看多了这些权重,你会明白所谓“黑箱”也没有那么黑。选模型时如果你需要向别人解释预测理由,逻辑回归这种透明模型往往比复杂模型更有优势。

4. 评估分类器不能只看准确率:从混淆矩阵开始

4.1 准确率很高,不代表模型真的好

训练完成后,最直接的评估指标是准确率,也就是预测正确的比例:

from sklearn.metrics import accuracy_score acc = accuracy_score(y_test, predictions) print(f"准确率: {acc:.2f}")

鸢尾花数据集上用逻辑回归,准确率通常在 0.9 以上,看起来确实不错。但如果你把准确率当作唯一指标,很快会栽跟头。举个极端例子:假设某种疾病的发病率只有 1%,你写一个模型无论输入什么都预测“没病”,准确率就是 99%。这个模型有用吗?完全没有。它一个病人都找不出来。

这就是我为什么坚持强调,评估分类模型要看多个维度,尤其是混淆矩阵。

4.2 混淆矩阵、精确率、召回率,分别回答什么问题

混淆矩阵是一张表格,行代表真实类别,列代表预测类别。主对角线上的数字是预测正确的样本数,其他位置则是错误情况。它真正回答了三个问题:哪些类别被分对了?哪些反而被分错了?分错的具体是哪两类之间?

在二分类场景下,混淆矩阵具体化为 4 个数值:真正例、假正例、真负例、假负例。再往下拆解,就有了两个新手常混淆的指标:

  • 精确率:预测为正类的样本里,有多少是真的正类。回答的是“我说它是猫,到底准不准”。
  • 召回率:所有真实正类样本里,我找回来了多少。回答的是“真实的猫有多少被我找出来了”。

这两个指标此消彼长,没有绝对的好坏,取决于你的业务目标。如果做垃圾邮件过滤,你宁可把一些正常邮件误判成垃圾(精确率稍稍受损),也不愿意放跑垃圾邮件,这时更看重召回率。如果做贷款审批,你把一个还不起钱的人放贷了损失巨大,这时更看重精确率。

4.3 多分类问题的评估:鸢尾花案例的解读

鸢尾花是三分类问题,评估思路和二分类本质上一样,只是把每个类别轮流当成“正类”来计算:

from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test, predictions)) print(classification_report(y_test, predictions, target_names=iris.target_names))

classification_report 会给每个类别列出精确率、召回率、F1 分数,以及整体的准确率和加权指标。读这张报告比只看准确率有用得多。你会发现某些类别召回率高、精确率低,或者反过来,这些差异往往能告诉你模型的偏好和数据的分布问题。

经验提示:如果你面对的是不平衡数据集,准确率几乎是没用的。直接把加权 F1 或宏观 F1 当作主看指标,再配合混淆矩阵观察具体错分情况,才能真实反映模型水平。

5. 实测中一定会踩的坑:shape、特征缩放和过拟合

5.1 “形状对不上”是新手报错第一杀手

第一次写代码,你会遇到的报错大概率是“形状对不上”。这类问题通常就是数据处理阶段留下的隐患。最常见的场景是:你用一个二维数组的某一行去预测,模型却说不行。

比如:

new_sample = X_test[0] # shape 是 (4,),不是 (1, 4) model.predict(new_sample) # 报错

解决办法是把它先变成二维:

model.predict(new_sample.reshape(1, -1))

reshape(1, -1) 的意思是,让它变成 1 行、列数自动推断的二维数组。我一直提醒团队的新同学:Scikit-learn 里的模型默认接受“样本数 × 特征数”的二维输入,单个样本也要套一个数组。

5.2 特征缩放不是可选项,差一个数量级就翻车

逻辑回归这类基于距离的线性模型,对特征的量纲很敏感。如果有一个特征取值是几万,另一个特征取值是零点几,模型会倾向于把大数值的特征当成主导,小数值的特征几乎被忽略,这往往不是我们想要的效果。

解决办法是标准化,也就是把每个特征变成均值 0、方差 1 的分布。Scikit-learn 提供了专门的工具:

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)

注意一个关键细节:fit_transform 只能用在训练集上,测试集上只能用 transform。这背后的原因很严谨——测试集是“没见过的题”,你在预处理阶段也不应该用它来计算任何统计量。如果测试集参与了均值计算,相当于漏了一手,指标就会虚高。

另一个细节是:训练完模型后,你预测新样本时也要先用同一个 scaler.transform 处理,而不是重新 fit。这个坑我见过很多人踩,每次都要反复提醒。

5.3 训练集表现远超测试集,说明你过拟合了

另一种常见情况是训练集准确率 1.0,测试集准确率掉到 0.8 以下。这就是教科书里说的过拟合——模型把训练样本记得太熟了,连噪声都背了下来,遇到没见过的新数据反而不灵了。

我初次遇到这种情况时很困惑,后来想到一个生活化类比。考试前你把练习册的答案一字不漏背下来,考到原题你能拿满分,但只要题目稍加改动就不会了。过拟合的模型也一样,它没有学到特征和标签之间普遍存在的规律,而是记住了训练数据里的个案。

应对方法有几个。第一个是增加训练数据量;第二个是降低模型复杂度,比如逻辑回归可以调高正则化强度;第三个是最常用的,使用交叉验证而不是一次性划分训练测试集,后面我会专门展开。

6. 从“第一个模型”到“能用的模型”:交叉验证与后续路线

6.1 交叉验证:更稳妥地评估模型

如果只划分一次训练集和测试集,评估结果会依赖那一刀切在哪儿——数据怎么分,可能让结果偏高或偏低。交叉验证的思路是把数据切成 K 份,每次拿 1 份当测试集,其余 K-1 份当训练集,轮流 K 次,最后看平均表现。Scikit-learn 里实现这个逻辑只需要一行:

from sklearn.model_selection import cross_val_score scores = cross_val_score(model, X_train_scaled, y_train, cv=5) print(scores) print(f"平均分数: {scores.mean():.3f}")

运行后你会得到 5 个分数,它们的平均值比单次划分的评估结果可靠得多。我把它当作基本操作而不是进阶技巧,因为只做一次 train_test_split 而完全不做交叉验证,评估的置信度确实有限。

6.2 超参数调优入门:别一上来就用网格搜索

模型的超参数是那些不通过学习得到、而要在训练前手工指定的参数。逻辑回归里 C 是正则化强度的倒数和 max_iter 控制最大迭代次数。新手容易直接上网格搜索,把所有参数组合跑一遍。这种做法的坏处是耗时,而且如果数据划分不稳定,超参数不一定能复现。

初期我更推荐一次只动一个参数,看交叉验证分数的变化。比如试试 C 从 0.1、1、10 里选,其他不动。这样你能建立对参数的直觉,而不是把调参工具当黑箱乱按。真正需要系统调参时再用网格搜索或随机搜索也不迟。

6.3 下一步:试试其他模型,但把流程保持统一

跑通逻辑回归后,你就有了一套标准流程:加载数据、划分数据、预处理、训练、评估、调参数。接下来可以试试 KNN、决策树、随机森林,代码框架几乎不变,只是换个模型名称。

我建议你刻意做一次对比实验:在同一个数据集上,用同一份预处理和同一套评估逻辑,分别跑 3 个模型,记录各自的混淆矩阵和 F1 分数。你会惊讶地发现,不同模型在同一个问题上各有各的优势区域,这比一个模型调到天荒地老更有收获。

个人体会是,学机器学习的真正支点并不是会用某个模型,而是建立起“数据 → 评估 → 迭代”的闭环思维。这个闭环一旦建立,后续学什么模型都是在往里填细节。把这个流程刻进肌肉记忆,比多背几种算法的名字重要得多。

如果你的时间有限,我建议你把今天这篇里从数据切分到交叉验证的全部代码,亲手敲一遍,不要复制。敲的过程会逼你理解每一行在干什么,这是看教程无论如何也替代不了的。完成之后,你已经拥有了实现和评估一个分类模型的完整能力,接下来就可以放心地往更多算法和真实数据上走了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 4:10:00

校园媒体活动推荐系统:基于SpringBoot+Vue的推荐算法与前后端实战

做校园媒体活动推荐系统,说实话一开始我只是想解决一个很现实的问题:活动太多,用户挑花了眼,主办方也摸不准什么人会来。后来把“基于SpringBootVue的媒体活动推荐系统”这个项目落地以后,我才发现推荐这件事真正难的不…

作者头像 李华
网站建设 2026/10/20 4:09:28

多智能体长会话Token刺客终结者:向量路由降本92%

如果你也在运行一个 OpenClaw 这类多智能体编排服务,大概率经历过这么一瞬间:打开账单,发现上个月的 API 费用凭空多出来一截,就像半夜有人悄悄刷了你的卡。我做过一个很粗糙的统计,在典型的长会话场景里,每…

作者头像 李华
网站建设 2026/10/20 4:09:01

基于TMS320F28335的工业级FOC电机控制固件

简介:本资源是一套基于TMS320F28335 DSP芯片实现电机磁场定向控制(FOC)与空间矢量脉宽调制(SVPWM)的完整嵌入式控制工程,面向电力电子、电机控制方向的本科生、研究生及工业自动化工程师,解决永…

作者头像 李华
网站建设 2026/10/20 4:08:50

YOLOX在水下目标检测中的应用:冷水珊瑚识别与ROV部署实践

1. 任务拆解与方案选型:冷水珊瑚检测到底难在哪Lophelia pertusa是冷水珊瑚里最典型的一种,常常在几百米甚至上千米深的水下形成大面积的珊瑚礁,是深海生态系统的关键栖息地。要监测它的分布和健康状况,靠潜水员不现实&#xff0c…

作者头像 李华
网站建设 2026/10/20 4:08:04

基于YOLOv11的昆虫识别检测系统:从数据集准备到UI界面实战

前阵子有位朋友跑来找我,他是做农田虫情监测的,手头攒了一堆不同环境光线下拍到的昆虫照片,想让我帮忙看看到底能不能用深度学习做一个自动识别的工具。我第一反应就是YOLOv11,毕竟它兼顾精度和速度,在实时检测场景里确…

作者头像 李华