第一个模型:用 scikit-learn 训练
这是什么:模型(model) = 机器从数据里学出来的"规律本体",一份能对新数据做出预测的产物;scikit-learn 是帮你训出它的 Python 库。
为什么用:概念篇结束,再背概念也学不会写代码——本篇正式动手,训出你人生第一个模型,把"模型"这两个字变成真跑起来的结果。
如何用:先 pip install scikit-learn,再拿机器学习界的"Hello World"鸢尾花数据集,四步训出模型。
安装 scikit-learn
scikit-learn 是 Python 最经典的机器学习库,常见算法全部内置,几行代码就能训模型。命令行执行:
pip install scikit-learn
装完后在 Python 里 import sklearn 不报错就 OK(它会自动带上 numpy 等依赖)。
认识鸢尾花数据集
我们用机器学习界的"Hello World"——鸢尾花数据集练手:150 朵鸢尾花,每朵记录了 4 个特征(花萼长宽、花瓣长宽,单位厘米),分属 3 个品种之一:
| 编号 | 名称 | 中文名 |
|---|---|---|
| 0 | setosa | 山鸢尾 |
| 1 | versicolor | 变色鸢尾 |
| 2 | virginica | 维吉尼亚鸢尾 |
任务:根据 4 个特征判断一朵花是哪个品种——典型的分类问题。
数据长这样(前 5 行)
花萼长 | 花萼宽 | 花瓣长 | 花瓣宽 | 品种
5.1 | 3.5 | 1.4 | 0.2 | setosa
4.9 | 3.0 | 1.4 | 0.2 | setosa
4.7 | 3.2 | 1.3 | 0.2 | setosa
4.6 | 3.1 | 1.5 | 0.2 | setosa
5.0 | 3.6 | 1.4 | 0.2 | setosa
四步训出第一个模型
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
# 第 1 步:加载数据
iris = load_iris()
X, y = iris.data, iris.target # X 是 150×4 的特征表,y 是 150 个品种编号
# 第 2 步:划分训练集和测试集(75% 刷题,25% 考试)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42)
# 第 3 步:创建模型并训练——K 近邻,找 3 个最近邻居"投票"
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
# 第 4 步:预测一朵新花(花萼长5.0宽3.5,花瓣长1.5宽0.5)
new_flower = [[5.0, 3.5, 1.5, 0.5]]
pred = model.predict(new_flower)
print("预测的品种编号:", pred)
print("品种名称:", iris.target_names[pred[0]])
你会看到:
预测的品种编号: [0]
品种名称: setosa
一朵花瓣又短又窄的花,模型判断它是山鸢尾。
代码逐行解读
先说个约定俗成:大写 X 表示特征表(二维),小写 y 表示标签列(一维),全世界的教程都这么写。
| 代码 | 在干什么 |
|---|---|
load_iris() |
加载内置的鸢尾花数据集 |
train_test_split(...) |
随机划分训练集/测试集;random_state=42 固定随机种子,保证每次运行结果一致 |
KNeighborsClassifier(n_neighbors=3) |
创建"K 近邻"分类器:新花来了,看周围 3 朵最近的花,少数服从多数 |
model.fit(X_train, y_train) |
训练:让模型刷训练集,记住特征与品种的关系 |
model.predict(new_flower) |
预测:给一朵没见过的新花定品种 |
记忆口诀:加载数据、划分数据、fit 训练、predict 预测——机器学习四步曲。
为什么选 K 近邻?
scikit-learn 内置了几十种算法,为什么第一个模型用 K 近邻(KNeighborsClassifier)?
- 直观:"物以类聚,新花看周围最近的几朵是什么品种,自己就是什么品种"
- 无训练过程:KNN 本质上不做复杂的数学优化,fit 只是把数据存起来,预测时才计算距离,快且易懂
- 分类和回归都能用:KNeighborsClassifier 做分类,KNeighborsRegressor 做回归
当然,KNN 也有缺点:数据量大时预测慢(要跟每个训练样本算距离),对特征缩放敏感。后面章节会逐步接触其他算法。
❓ 常见问题
Q1:random_state=42 有什么意义?
它固定了随机种子。没有它,每次运行 train_test_split 都会随机划分不同的训练/测试集,导致结果每次不一样。设成 42 后,你和别人运行同样的代码,得到的划分完全一致,方便对比和调试。
Q2:n_neighbors=3 怎么选?3 是不是最好的?
不是固定的。3 是常见起始值。太小(如 1)容易过拟合(只看最近一朵,易受噪音干扰);太大(如 50)可能把太远的花也算进去,稀释了邻居的参考价值。后面可以尝试 1、5、7、9,看测试集准确率变化。
Q3:iris.target_names[pred[0]] 这里为什么要 [0]?
model.predict 返回的是一个数组,即使只传了一朵花,结果也是 [0] 这样的列表形式。pred[0] 取出第一个(也是唯一一个)预测编号,再用它去索引品种名称。
⚠️ 新手翻车现场
翻车一:忘记划分训练集/测试集,直接在全数据上 fit 和 score
# 错误:全数据训练,全数据打分
model.fit(X, y)
print(model.score(X, y)) # 永远很高,但没参考价值
问题:这是"刷题册当考卷",分数虚高,无法反映模型对新数据的真实表现。
修正:始终用 train_test_split 拆分,fit 用训练集,score 用测试集。
翻车二:把标签编号当连续数字做回归
# 错误:把品种编号 0、1、2 当数字,用线性回归预测
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y) # y 是 0/1/2,但品种没有大小顺序
问题:品种是类别,0 不代表"比 1 小",用回归没有意义。分类任务要用分类器(如 KNeighborsClassifier),回归任务才用回归器(如 LinearRegression)。
修正:明确任务类型,分类用分类器,回归用回归器。
📦 换皮小示例:用 KNN 做"水果分类"
把鸢尾花的套路套在水果上(特征:重量、甜度,标签:苹果/香蕉/橙子):
from sklearn.neighbors import KNeighborsClassifier
# [重量(g), 甜度(1-10)] -> 标签:0=苹果, 1=香蕉, 2=橙子
X = [[150, 7], [160, 8], [120, 6], [180, 9], [130, 5], [110, 4]]
y = [0, 0, 0, 0, 1, 1] # 简化示例,实际应更均衡
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X, y)
# 预测一个新水果:重量 140g,甜度 7
pred = model.predict([[140, 7]])
print("预测品种编号:", pred)
🎯 什么时候用 K 近邻
- 数据量不大(千级到万级)
- 特征之间没有复杂的非线性关系
- 需要模型结果容易解释("最近邻投票"很直观)
- 做分类或回归的基准对比(先用 KNN 跑个底,再换复杂模型)
📝 本章小结
- 机器学习四步曲:加载数据 → 划分训练/测试集 → fit 训练 → predict 预测
- 大写 X 是特征表,小写 y 是标签列
random_state=42固定随机种子,保证结果可复现- KNN 原理直观:周围 3 朵最近的花是什么品种,自己就是什么品种
- 分类用分类器,回归用回归器,别混
- 记忆口诀:加载数据、划分数据、fit 训练、predict 预测——机器学习四步曲。
动手改
- 把
n_neighbors改成 1 或 7,预测结果变了吗? - 预测另一朵花
[6.5, 3.0, 5.5, 2.0],看看是什么品种(提示:花瓣又长又宽) - 加一行
print(X_train.shape, X_test.shape),看看训练集和测试集各有多少朵花 - 尝试把
KNeighborsClassifier换成from sklearn.tree import DecisionTreeClassifier的决策树,看准确率差异
下一章:模型评估,这个模型到底几分?学会给模型打分 🐸