第 19 章 用分类模型识别类别
文章目录
- [第 19 章 用分类模型识别类别](#第 19 章 用分类模型识别类别)
-
- [🌈 关于《AI 零基础 36 讲》](#🌈 关于《AI 零基础 36 讲》)
- [1. 先确认要分的类别](#1. 先确认要分的类别)
- [2. 逻辑回归怎样给出分类概率](#2. 逻辑回归怎样给出分类概率)
- [3. 概率的列顺序必须跟类别对上](#3. 概率的列顺序必须跟类别对上)
- [4. 混淆矩阵把错法摆出来](#4. 混淆矩阵把错法摆出来)
- [5. 决策边界是输入空间里的分界](#5. 决策边界是输入空间里的分界)
- [6. 找到两条分错的花](#6. 找到两条分错的花)
- [7. 在自己的电脑上运行](#7. 在自己的电脑上运行)
- [8. 独立练习](#8. 独立练习)
输入一朵花的四个测量值,模型返回 versicolor。第 17 章已经跑通过这个流程,但结果里还有一个问题没有展开。模型在几个类别之间怎样作出选择,选错时又留下了什么线索?
本章沿用第 17 章的公开 Iris 数据与固定划分,训练一个逻辑回归分类器。读完后,你会得到每条测试记录的类别概率、一张混淆矩阵、一个单条预测入口,并能指出两条分错记录中的具体差异。请先熟悉训练测试划分与 Pandas 的列选择。全部实测结果来自本章代码,概率位置练习使用明确标注的教学数字。

🌈 关于《AI 零基础 36 讲》
🧠 零基础也能开始学 AI
《AI 零基础 36 讲》是一套面向初学者的 AI 入门教程。课程从认识和使用 AI 开始,逐步学习
Python、数据处理、机器学习与深度学习,再进入大模型应用开发,最后完成个人知识库助手的综合实践。
📖 本篇是正式讲解文章
通过具体例子、原创图示和操作结果讲清概念。涉及编程的章节提供可运行代码,方便你边读边试。
🎯 读完以后,动手检验
建议按专栏顺序学习,并完成对应的课后训练,检查自己能否独立运用本章知识。
博客专栏:《AI 零基础 36 讲》
1. 先确认要分的类别
Iris 数据一共有 150 条花卉测量记录。每条包括萼片长度、萼片宽度、花瓣长度、花瓣宽度,单位都是厘米。标签有三个取值,0 表示 setosa,1 表示 versicolor,2 表示 virginica。数字只是类别编码,类别 2 不代表比类别 1 大一倍。
本章复制第 17 章固定快照,数值没有改动。来源、许可与 SHA256 校验记录见数据说明。编号用于找回原始行,训练输入中没有编号和目标标签。读者若自行添加字段,先问一遍预测新花时能否拿到它。只有看过标准答案才知道的字段不能当输入。
先数清每个类别有多少条。
python
from examples.project_core import load_dataset, split_dataset
frame = load_dataset()
train, test = split_dataset(frame)
for name, data in [("全部", frame), ("训练", train), ("测试", test)]:
print(name, data.target.value_counts().sort_index().tolist())
输出依次为 [50, 50, 50]、[40, 40, 40]、[10, 10, 10]。这里使用分层划分,划分时尽量保留各类别的比例。训练 120 条,测试 30 条,固定种子仍为 42,与第 17 章完全一致。
类别不平衡指某些类别的样本明显少于另一些类别。本章三类一样多,没有观察到数量不平衡,也就没有为了流程齐全强加类别权重。真实数据若有 950 条正常信息和 50 条垃圾信息,一个全猜正常的模型也能达到 95% 准确率。这个数字解释不了垃圾信息是否被识别,下一章会实际计算这种情况。
平衡的数据仍可能存在采样范围限制。150 条旧测量记录不能覆盖所有测量设备、拍摄环境或新花卉种类。当前输入是测量表格,程序没有读取照片。
2. 逻辑回归怎样给出分类概率
逻辑回归的名称里有"回归",在这里承担的是分类任务。它先根据输入和学到的系数计算各类别分数,再把分数转换成类别概率。这个三分类实验使用 lbfgs 求解器,对三个类别共同建模。
先沿用第 17 章的完整 Pipeline。Pipeline 把标准化与分类器串在一起,标准化只用训练行计算均值和尺度。预测测试记录时,沿用训练中保存的统计量。这样既不会把测试数据带入训练,也减少了预测时忘记标准化的机会。
python
from examples.classification_core import experiment
from examples.project_core import FEATURES
model, boundary, train, test, summary = experiment()
print("类别顺序", model.classes_)
print("概率形状", model.predict_proba(test[FEATURES]).shape)
print("标准化看到的训练条数", model.named_steps["scale"].n_samples_seen_)
运行结果中的类别顺序是 [0 1 2],概率形状是 (30, 3),标准化看到的训练条数是 120。30 行对应 30 朵测试花,三列对应三个类别。新术语 predict_proba 的作用就是返回各类别概率,predict 直接返回预测标签。
概率数值在零到一之间,每一行合计约为一,浮点计算会有很小的舍入差异。它们反映当前模型对输入的判断。本章没有做概率校准,也没有检验"输出 0.8 的样本是否约有八成答对",因此不能把一个 0.8 直接当作可靠性保证。概率校准需要另外留出合适的数据进行检验。
3. 概率的列顺序必须跟类别对上
下面使用公开表第一行的四个数值,只演示接口。它来自已有数据,不能当作从未见过的新花来报告效果。
python
from examples.classification_core import experiment, predict_one_with_proba
model, _, _, _, _ = experiment()
result = predict_one_with_proba(model, [5.1, 3.5, 1.4, 0.2])
print(result["name"])
for name, probability in result["probabilities"].items():
print(name, f"{probability:.6f}")
输出类别为 setosa,三类概率约为 0.980813、0.019187、0.000000。最后一项完整精度约为 2.697e-7,显示为六位小数时舍入到了零。展示舍入不改变原始计算。
本章采用最高概率对应的类别作为标签。找最大值时,argmax() 返回的是位置。只有用这个位置去索引 model.classes_,才拿到了对应类别。下面刻意打乱类别顺序,数字为原创教学设定。
python
import numpy as np
classes = np.array([2, 0, 1])
probabilities = np.array([0.7, 0.2, 0.1])
position = probabilities.argmax()
print("最大值位置", position)
print("对应类别", classes[position])
输出最大值位置 0,对应类别 2。直接把位置 0 当成类别 0,会把概率读错。本章计算模块将标签与对应概率一起返回,八项测试中也专门检查这个顺序。
4. 混淆矩阵把错法摆出来
测试集 30 条,模型答对 28 条,准确率为 28 / 30,约 93.33%。这个结果与第 17 章一致,添加概率输出没有重新选择划分或修改模型来提高分数。
仅看 93.33%,你还不知道哪两个类别混在了一起。混淆矩阵是一张按真实类别与预测类别交叉计数的表。本章横轴是预测类别,纵轴是真实类别,每个格子数的是记录条数。

| 真实类别 | 预测 setosa | 预测 versicolor | 预测 virginica |
|---|---|---|---|
| setosa | 10 | 0 | 0 |
| versicolor | 0 | 9 | 1 |
| virginica | 0 | 1 | 9 |
从左上到右下的三个格子是正确预测,加起来为 28。真实 versicolor 那一行最后一格为 1,表示一朵 versicolor 被判断为 virginica。真实 virginica 那一行中间一格也为 1,表示一次相反方向的错误。setosa 的十条测试记录都正确。
矩阵中的零只能描述这 30 条测试记录,不能证明某类永远不会分错。每一类仅有十条测试记录,增加一条错误就会使这一类的正确比例变动十个百分点,结果对小样本相当敏感。
5. 决策边界是输入空间里的分界
决策边界指模型预测类别发生变化的位置。输入只有两项时,可以把每组输入画成平面中的一个点,为平面上很多位置分别预测类别,再用背景颜色画出区域。
四特征主模型需要四个输入。直接在二维图中忽略两个输入,会让读者误以为背景能代表它的完整判断。本章为画图额外训练了一个只使用花瓣长宽的模型,仍只用原来的 120 条训练记录。

横轴是花瓣长度,纵轴是花瓣宽度。圆点对应训练记录,三角对应测试记录,点的颜色表示真实标签,浅色背景表示两特征模型的预测。两种颜色不同,就表示这个两特征模型在该点分错了。测试点只在训练结束后叠加,未用于拟合背景。
图中 setosa 集中在花瓣较短较窄的一侧,另两类在中间与右上方有重叠。背景分界来自训练后的模型,不是人为圈出的三组范围。本次两特征测试准确率也为 93.33%,与四特征主模型数值相同。相同分数不能证明两个模型在每一条记录上做出了相同预测。
在四维输入空间里,分界不能靠这张二维图完整呈现。另一种画法是固定其余两项后画一个切片,但必须写明固定值。本章选择单独训练两特征模型,让图的输入与计算保持一致。
6. 找到两条分错的花
逐条预测表保留编号、四项测量、真实标签与三项概率。两条错误分别为 iris-134 与 iris-077。
| 编号 | 真实类别 | 预测类别 | versicolor 概率 | virginica 概率 |
|---|---|---|---|---|
| iris-134 | virginica | versicolor | 0.5145 | 0.4842 |
| iris-077 | versicolor | virginica | 0.4417 | 0.5569 |
第一条花瓣长 5.6 厘米、宽 1.4 厘米,第二条长 5.0 厘米、宽 1.7 厘米。这两条的最高两个概率都比较接近,第一条仅差约 0.0303。模型最终仍要给出一个标签,小差距在这里提醒我们去查看测量和原标签。

当前材料只能证明两条记录在现有测量与模型下分错了。我们没有原始花卉照片或复测记录,无法判定具体哪一项测量出了问题,也不能因为预测不同就改掉真实标签。两条记录提供了复核入口,没有提供修改标签的证据。
测试集中最高两类概率差距最小的五条记录里,后三条预测正确。差距小适合用来安排人工检查,不能直接等同于错误。若准备把低概率差距的记录交给人工,需要在验证集上决定规则,再在独立测试数据上检查成本与效果。
7. 在自己的电脑上运行
从本章目录运行,依赖版本已经固定。
powershell
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe examples/run_classification.py
.\.venv\Scripts\python.exe examples/predict.py 5.1 3.5 1.4 0.2
.\.venv\Scripts\python.exe -m unittest discover -s tests -v
主程序生成 results/model.joblib、预测表、混淆矩阵和三张图。预测入口加载本地生成的模型,输出标签、名称和类别概率。校验值用于发现文件被改动,文件来源仍需要可信。不要加载来路不明的模型文件。
打开 Notebook前,再安装 requirements-notebook.txt,选择刚创建的环境,先运行主程序生成图。Notebook 中保留了七个实际执行的代码单元格。
单条输入报二维数组错误时,查看错误与修复记录。四个数字需要组成"一行四列"的输入,本章预测入口已处理这个转换。若提示字段数量不对或测量无效,检查是否少了一个数、混入标签,或输入了零、负数、缺失值。四个测量顺序固定,厘米和毫米也不能混用。
缺少模型文件时,先运行训练入口。更换依赖版本后,也先重新训练,再做预测,避免沿用其他版本保存的对象。
8. 独立练习
从 test_predictions.csv 找出 iris-138,读出真实类别、最高概率类别及最高两项概率差。将它与 iris-134 对照,说明小差距为何只能提醒复核。再用混淆矩阵手算 virginica 的十条真实记录中有几条被识别正确。
完整练习与参考答案见【零基础学AI】第 19 章课后练习与答案。先在纸上判断,再用代码核对表格。