sklearn手写数字识别实战:KNN与逻辑回归的多模型对比与性能优化

1次阅读
没有评论

共计 2963 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

背景介绍

手写数字识别是计算机视觉和机器学习中的经典问题,广泛应用于邮政编码识别、银行支票处理、表单数据录入等场景。MNIST 数据集作为该领域的基准数据集,包含 60,000 个训练样本和 10,000 个测试样本,每个样本是 28×28 像素的灰度图像,对应 0 - 9 的手写数字。

sklearn 手写数字识别实战:KNN 与逻辑回归的多模型对比与性能优化

尽管深度学习在图像识别领域取得了显著进展,但传统机器学习算法如 KNN 和逻辑回归因其简单高效、可解释性强等优势,在某些场景下仍具实用价值。本文将系统对比这两种算法在实际任务中的表现。

数据准备

首先加载并预处理 MNIST 数据集。sklearn 提供了简化版的 MNIST 数据集(原始数据的子集),适合快速实验:

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
import numpy as np

# 加载数据
mnist = fetch_openml('mnist_784', version=1, as_frame=False)
X, y = mnist.data, mnist.target.astype(np.uint8)

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 特征缩放(重要!)X_train = X_train / 255.0
X_test = X_test / 255.0

关键预处理步骤:
– 像素值归一化到 [0,1] 区间(原始像素值为 0 -255)
– 标签转换为整数类型
– 保留 20% 数据作为测试集

模型实现

KNN 分类器

K 近邻算法通过比较样本间的距离进行分类:

from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# 初始化模型(默认 k =5)knn = KNeighborsClassifier()

# 训练模型
knn.fit(X_train, y_train)

# 预测测试集
y_pred_knn = knn.predict(X_test)

# 计算准确率
acc_knn = accuracy_score(y_test, y_pred_knn)
print(f"KNN 准确率: {acc_knn:.4f}")

逻辑回归分类器

逻辑回归虽然名为 ” 回归 ”,实为分类算法,通过 sigmoid 函数输出概率:

from sklearn.linear_model import LogisticRegression

# 使用多分类设置和增加最大迭代次数
log_reg = LogisticRegression(multi_class='multinomial', solver='lbfgs', max_iter=1000)

# 训练模型(可能较慢)log_reg.fit(X_train, y_train)

# 预测测试集
y_pred_log = log_reg.predict(X_test)

# 计算准确率
acc_log = accuracy_score(y_test, y_pred_log)
print(f"逻辑回归准确率: {acc_log:.4f}")

性能对比

我们通过多个维度量化比较两种模型:

  1. 准确率对比
  2. KNN: 约 96.8%
  3. 逻辑回归: 约 91.5%

  4. 训练时间

  5. KNN: 几乎无需训练(惰性学习)
  6. 逻辑回归: 在 CPU 上约 1 - 2 分钟

  7. 预测速度

  8. KNN: 较慢(需计算与所有训练样本的距离)
  9. 逻辑回归: 极快(只需计算权重向量点积)

可视化混淆矩阵(以 KNN 为例):

from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

cm = confusion_matrix(y_test, y_pred_knn)
plt.figure(figsize=(10,8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.title('KNN 混淆矩阵')
plt.show()

参数调优

KNN 调优

关键参数是 n_neighbors(k 值)和距离度量方式:

from sklearn.model_selection import GridSearchCV

param_grid = {'n_neighbors': [3, 5, 7],
    'weights': ['uniform', 'distance'],
    'metric': ['euclidean', 'manhattan']
}

grid_search = GridSearchCV(KNeighborsClassifier(), param_grid, cv=3, verbose=2)
grid_search.fit(X_train[:5000], y_train[:5000])  # 为节省时间使用子集

print("最佳参数:", grid_search.best_params_)
print("最佳交叉验证准确率:", grid_search.best_score_)

逻辑回归调优

主要调整正则化强度 C 和惩罚类型:

param_grid = {'C': [0.1, 1, 10],
    'penalty': ['l2']  # MNIST 数据通常 l2 优于 l1
}

grid_search = GridSearchCV(LogisticRegression(multi_class='multinomial', solver='lbfgs', max_iter=1000),
    param_grid, cv=3, verbose=2
)
grid_search.fit(X_train[:5000], y_train[:5000])

print("最佳参数:", grid_search.best_params_)
print("最佳交叉验证准确率:", grid_search.best_score_)

避坑指南

  1. 特征缩放必要性
  2. KNN 对特征尺度敏感,必须归一化
  3. 逻辑回归虽不严格要求,但能加速收敛

  4. 类别不平衡处理

  5. MNIST 数据较平衡,但实际应用中可考虑:

    • class_weight 参数
    • 过采样 / 欠采样技术
  6. 内存问题

  7. KNN 需存储全部训练数据,大数据集时内存消耗高
  8. 可考虑 KD 树或 Ball 树优化

  9. 收敛警告处理

  10. 逻辑回归可能出现 ” 未收敛 ” 警告
  11. 增加 max_iter 或调整 tol 参数

总结与展望

算法选择建议

  • 选择 KNN 当:
  • 需要快速原型验证
  • 数据规模适中
  • 解释预测结果有意义(通过近邻样本)

  • 选择逻辑回归当:

  • 需要部署到生产环境(预测速度快)
  • 需要模型系数解释特征重要性
  • 处理更高维数据(KNN 面临维度灾难)

优化方向

  1. 特征工程:
  2. 添加方向梯度直方图 (HOG) 等特征
  3. 使用 PCA 降维

  4. 模型融合:

  5. 结合 KNN 和逻辑回归的投票分类器

  6. 进阶模型:

  7. 随机森林
  8. 支持向量机
  9. 简单的神经网络

思考题

  1. 如何修改代码实现一个加权投票的 KNN 分类器(不同距离的邻居具有不同投票权重)?
  2. 对于逻辑回归,当某个数字类别(如 ”1″)的识别准确率明显低于其他数字时,可以采取哪些针对性的改进措施?
  3. 如果要在移动设备上部署手写数字识别模型,在 KNN 和逻辑回归中你会选择哪个?需要考虑哪些因素?
正文完
 0
评论(没有评论)