一张图片怎样成为分类器的输入?识别结果中的“97%”又具体说明什么?scikit-learn 的手写数字示例把这两个问题串成了一个完整过程:读取内置的 8×8 灰度图,将像素展开为特征,训练支持向量分类器,再用逐类报告和混淆矩阵检查错误。
本文根据 scikit-learn developers 的 Recognizing hand-written digits 翻译整理,覆盖该示例的全部技术步骤。2026-10-05 核对页面显示 scikit-learn 1.9.1;stable 链接会随版本变化。下文引用的分数来自原网页输出,本次没有运行训练或测试。

先认识输入:图像、标签和样本矩阵
datasets.load_digits() 读取随 scikit-learn 提供的教学数据,不需要本示例另行下载图像。digits.images 为每张图像保存一个 8×8 灰度数组,digits.target 则保存它代表的数字,类别为 0 到 9。原文先显示前四张图,并把真实标签放到标题中,借此确认输入与标签的对应关系。
灰度图的二维形状适合人观察,分类器却需要形如 (n_samples, n_features) 的二维样本表。reshape((n_samples, -1)) 保留样本这一维,把每张图的 64 个像素依次放到一行中。这里没有增加信息,也没有提取笔画特征;它只是改变数组形状。预测后若要显示图像,可以把一行 64 维特征恢复成 (8, 8)。
原文提到,如果输入来自 PNG 等文件,可以使用 matplotlib.pyplot.imread 读取。那只是读文件的入口,并不意味着任意图片都可直接传给当前模型。图片大小、通道数、灰度范围、前景背景方向和数字的位置都必须与训练输入相容;这些真实图片预处理工作不在本示例范围内。
保持示例的划分和模型参数
分类器是 svm.SVC(gamma=0.001)。原文只显式给出 gamma,它影响默认 RBF 核对样本间距离的敏感程度;这个值是本教学示例的参数,并非适用于所有手写图像的通用选择。
训练和测试各占约一半,关键参数是 shuffle=False。它让样本保持原顺序,前一部分用于训练,后一部分用于测试。改变为随机或分层划分会改变实验条件,不能继续把原文的结果当作同一次实验。训练使用 fit(X_train, y_train),测试仅调用 predict(X_test),标签 y_test 留到评估时使用。
下面将原页面的分段代码合并为一段可阅读的完整示例。除中文注释、首组标题改用等价的 f-string,以及合并重复的输出标题外,数据载入、划分、模型、显示和评估逻辑保持原样。代码未执行。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
import matplotlib.pyplot as plt
from sklearn import datasets, metrics, svm
from sklearn.model_selection import train_test_split
digits = datasets.load_digits()
# 先查看前四张图像和真实标签。
_, axes = plt.subplots(nrows=1, ncols=4, figsize=(10, 3))
for ax, image, label in zip(axes, digits.images, digits.target):
ax.set_axis_off()
ax.imshow(image, cmap=plt.cm.gray_r, interpolation="nearest")
ax.set_title(f"Training: {label}")
n_samples = len(digits.images)
data = digits.images.reshape((n_samples, -1))
clf = svm.SVC(gamma=0.001)
X_train, X_test, y_train, y_test = train_test_split(
data, digits.target, test_size=0.5, shuffle=False
)
clf.fit(X_train, y_train)
predicted = clf.predict(X_test)
_, axes = plt.subplots(nrows=1, ncols=4, figsize=(10, 3))
for ax, image, prediction in zip(axes, X_test, predicted):
ax.set_axis_off()
ax.imshow(image.reshape(8, 8), cmap=plt.cm.gray_r,
interpolation="nearest")
ax.set_title(f"Prediction: {prediction}")
print(metrics.classification_report(y_test, predicted))
disp = metrics.ConfusionMatrixDisplay.from_predictions(y_test, predicted)
disp.figure_.suptitle("Confusion Matrix")
print(disp.confusion_matrix)
plt.show()
# 原例标签恰好为连续整数 0 到 9,因此行列下标就是类别。
y_true, y_pred = [], []
cm = disp.confusion_matrix
for gt in range(len(cm)):
for pred in range(len(cm)):
y_true += [gt] * cm[gt][pred]
y_pred += [pred] * cm[gt][pred]
print(metrics.classification_report(y_true, y_pred))
从报告中区分几种“好坏”
classification_report 为每个数字列出 precision、recall、f1-score 和 support。precision 回答“被预测为该数字的样本中,有多少真的属于它”;recall 回答“真实属于该数字的样本中,有多少被找出来”。F1 是精确率和召回率的调和平均数,support 是测试集中该类别的真实样本数。
原网页的报告包含 899 个测试样本,accuracy 四舍五入为 0.97。宏平均 macro avg 对各类别等权平均,加权平均 weighted avg 则按 support 加权。两个汇总值相近,不意味着每个数字都一样容易识别:原文中数字 3 的召回率为 0.87,低于整体水平;数字 8 的召回率为 1.00,但精确率为 0.94,说明所有真实的 8 都找到了,同时别的数字也有被误判成 8 的情况。
这些数字只对应原文页面展示的数据、参数和划分方式。它们既不是本文重新训练的结果,也不是对手机拍照、票据或其他手写体输入的识别率承诺。
混淆矩阵说明错在什么地方
ConfusionMatrixDisplay.from_predictions(y_test, predicted) 以真实类别为行、预测类别为列统计数量。对角线表示预测正确的样本,非对角线说明具体的误判方向。例如原文矩阵中,真实数字 3 的一行有 79 个被预测为 3、3 个被预测为 5、4 个被预测为 7、5 个被预测为 8;这一行合计 91 个样本,解释了它较低的召回率。
矩阵也能校验报告。某类别的对角线值除以行和,得到该类别的召回率;除以列和,得到该类别的精确率。对角线总和除以矩阵总和,则得到整体准确率。把汇总分数与错误去向一起看,比只看准确率更容易判断下一步应检查哪些图像。
只有混淆矩阵,也能重建分类报告
示例最后遍历矩阵的每个单元格。若第 gt 行、第 pred 列的计数为 k,就在真实标签列表中加入 k 个 gt,在预测标签列表中加入 k 个 pred。两份标签再次传给 classification_report,即可重建相同的按类别统计。
这一步恢复的是计数关系,无法恢复原始样本顺序、图像内容或预测置信度。本例的类别刚好是连续整数 0—9,循环下标可以直接当标签;若类别为字符串或不连续整数,必须保存行列使用的类别顺序,并映射回真实标签。另外,逐项展开会消耗与样本总数成正比的内存,超大矩阵应直接根据计数计算指标,不能把这段教学写法无条件扩展到海量数据。
复现边界与静态审核
本例没有网络请求、硬编码秘密、动态代码执行或删除文件操作。静态检查没有发现直接的命令注入或 SQL 注入入口,但这不构成“没有漏洞”的保证。显示图像需要合适的 Matplotlib 后端;运行环境、包版本和绘图窗口可用性尚未实测。
若把示例扩展为服务,应为输入的图像尺寸和数据量设置上限,并先验证数据分布,再考虑重新训练、交叉验证和参数选择。不要为复现教学数字而把测试标签混入训练,也不要把源站运行结果贴上“本机测试通过”的标签。
原作与代码:scikit-learn developers。原网页版权标示 © 2007–2026 scikit-learn developers,示例代码 SPDX:BSD-3-Clause。自行绘制流程图署名未完纪。代码许可完整文本见下方,来源副本为 LICENSE-scikit-learn.txt。来源:官方完整示例。
版权与许可全文
BSD 3-Clause License Copyright (c) 2007-2026, The scikit-learn developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
原文图示与结果



源站完整评估输出
以下两份分类报告和混淆矩阵逐字保留自原文输出。后一份分类报告由混淆矩阵的计数重建,和前一份一致;这些输出均不是本文重新训练或运行所得。
Classification report for classifier SVC(gamma=0.001):
precision recall f1-score support
0 1.00 0.99 0.99 88
1 0.99 0.97 0.98 91
2 0.99 0.99 0.99 86
3 0.98 0.87 0.92 91
4 0.99 0.96 0.97 92
5 0.95 0.97 0.96 91
6 0.99 0.99 0.99 91
7 0.96 0.99 0.97 89
8 0.94 1.00 0.97 88
9 0.93 0.98 0.95 92
accuracy 0.97 899
macro avg 0.97 0.97 0.97 899
weighted avg 0.97 0.97 0.97 899
Confusion matrix: [[87 0 0 0 1 0 0 0 0 0] [ 0 88 1 0 0 0 0 0 1 1] [ 0 0 85 1 0 0 0 0 0 0] [ 0 0 0 79 0 3 0 4 5 0] [ 0 0 0 0 88 0 0 0 0 4] [ 0 0 0 0 0 88 1 0 0 2] [ 0 1 0 0 0 0 90 0 0 0] [ 0 0 0 0 0 1 0 88 0 0] [ 0 0 0 0 0 0 0 0 88 0] [ 0 0 0 1 0 1 0 0 0 90]]
Classification report rebuilt from confusion matrix:
precision recall f1-score support
0 1.00 0.99 0.99 88
1 0.99 0.97 0.98 91
2 0.99 0.99 0.99 86
3 0.98 0.87 0.92 91
4 0.99 0.96 0.97 92
5 0.95 0.97 0.96 91
6 0.99 0.99 0.99 91
7 0.96 0.99 0.97 89
8 0.94 1.00 0.97 88
9 0.93 0.98 0.95 92
accuracy 0.97 899
macro avg 0.97 0.97 0.97 899
weighted avg 0.97 0.97 0.97 899












暂无评论内容