机器学习基础--基于常用分类算法实现手写数字识别

# 1.数据介绍

>MNIST 数据集来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST). 训练集 (training set) 由来自 250 个不同人手写的数字构成, 其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员. 测试集(test set) 也是同样比例的手写数字数据.

>MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分:

* Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本)

* Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)

* Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)

* Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)

数据文件是二进制格式的,所以要按字节读取。代码如下:

导入函数包

python 复制代码
import struct,os
import numpy as np
from array import array as pyarray
from numpy import append, array, int8, uint8, zeros
import matplotlib.pyplot as plt
python 复制代码
def load_mnist(image_file, label_file, path="mnist"):
    digits=np.arange(10)

    fname_image = os.path.join(path, image_file)
    fname_label = os.path.join(path, label_file)

    flbl = open(fname_label, 'rb')
    magic_nr, size = struct.unpack(">II", flbl.read(8))
    lbl = pyarray("b", flbl.read())
    flbl.close()

    fimg = open(fname_image, 'rb')
    magic_nr, size, rows, cols = struct.unpack(">IIII", fimg.read(16))
    img = pyarray("B", fimg.read())
    fimg.close()

    ind = [ k for k in range(size) if lbl[k] in digits ]
    N = len(ind)

    images = zeros((N, rows*cols), dtype=uint8)
    labels = zeros((N, 1), dtype=int8)
    for i in range(len(ind)):
        images[i] = array(img[ ind[i]*rows*cols : (ind[i]+1)*rows*cols ]).reshape((1, rows*cols))
        labels[i] = lbl[ind[i]]

    return images, labels


train_image, train_label = load_mnist("train-images-idx3-ubyte", "train-labels-idx1-ubyte")
test_image, test_label = load_mnist("t10k-images-idx3-ubyte", "t10k-labels-idx1-ubyte")

定义加载mnist数据集的函数,传入参数为文件名称和路径,首先将路径拼接为文件所在路径,然后以二进制读方式打开文件

magic_nr, size = struct.unpack(">II", flbl.read(8))

">II" 表示总共读取两个 4 字节无符号整数。I :表示读取一个无符号的 4 字节整数(unsigned int),>:表示大端字节序(Big Endian)。flbl.read(8)表示读取前八个字节

lbl = pyarray("b", flbl.read())

使用 pyarray 将标签数据存储为一个高效的数组。flbl.read()读取剩余所有内容,这个是接着上面的八字节继续读取

ind = [k for k in range(size) if lbl[k] in digits]

N = len(ind)

  • 仅选择标签在 digits 范围(0 到 9)内的图像索引,存储到 ind
  • N 是符合条件的图像数量。

images = zeros((N, rows*cols), dtype=uint8) labels = zeros((N, 1), dtype=int8)

  • images: 用于存储图像数据,形状为 (N, rows*cols),每个图像展平成一维向量。
  • labels: 用于存储标签,形状为 (N, 1)

for i in range(len(ind)): images[i] = array(img[ind[i]*rows*cols : (ind[i]+1)*rows*cols]).reshape((1, rows*cols)) labels[i] = lbl[ind[i]]

  • 遍历筛选后的图像索引 ind
  • 根据索引从 img 中提取相应的图像像素数据,展平为一维并存储到 images
  • 将对应的标签存储到 labels

算法介绍

1. K-Nearest Neighbors (KNN)
  • 概念:

    K-Nearest Neighbors(KNN)是一种基于实例的学习算法。当给定一个新的数据点时,KNN 算法通过计算这个点与训练数据中所有点的距离,找到 K 个距离最近的点,然后通过这些 K 个邻居的标签来决定新的数据点的分类标签。

  • 特点:

    • 非参数方法:KNN 不对数据做任何假设。
    • 计算开销大:需要计算与所有训练样本的距离,因此在数据量大的时候计算成本高。
    • 适合小规模数据集,且对噪声敏感。
  • 工作原理:

    • 选择合适的 K 值(K 是邻居的数量)。
    • 计算测试样本与所有训练样本的距离(通常使用欧氏距离)。
    • 选出 K 个最近的邻居。
    • 通过邻居的标签投票决定分类。
python 复制代码
from sklearn.metrics import accuracy_score,classification_report
from sklearn.neighbors import KNeighborsClassifier

knc = KNeighborsClassifier(n_neighbors=10)
#初始化,设定要分类的个数为10
knc.fit(train_image,train_label.ravel())
#使用训练数据来训练Knn模型
predict = knc.predict(test_image)
print("accuracy_score: %.4lf" % accuracy_score(predict,test_label))
2. Naive Bayes
  • 概念:

    Naive Bayes 是一种基于贝叶斯定理的分类算法,假设特征之间是条件独立的(即"朴素"假设)。尽管这种假设在实际中很少成立,但 Naive Bayes 在许多实际问题中表现得很好。

  • 特点:

    • 计算速度快。
    • 对小数据集表现良好。
    • 假设特征独立:适用于条件独立的特征,如文本分类中的词频。
  • 工作原理:

    • 通过贝叶斯定理计算每个类别的后验概率:P(Y∣X)=P(X∣Y)P(Y)P(X)P(Y∣X)=P(X)P(X∣Y)P(Y)其中 P(Y∣X)P(Y∣X) 是给定特征 XX 后属于某类别 YY 的概率,P(X∣Y)P(X∣Y) 是特征 XX 在类别 YY 下的条件概率,P(Y)P(Y) 是类别 YY 的先验概率。
    • 由于假设特征条件独立,可以将特征的联合概率分解为单个特征的条件概率的乘积。
  • 适用场景:

    • 文本分类、垃圾邮件过滤、情感分析。
python 复制代码
from sklearn.naive_bayes import MultinomialNB

mnb = MultinomialNB()
mnb.fit(train_image,train_label)
predict = mnb.predict(test_image)
print("accuracy_score: %.4lf" % accuracy_score(predict,test_label))
print("Classification report for classifier %s:\n%s\n" % (mnb, classification_report(test_label, predict)))
3. Decision Tree(决策树)
  • 概念:

    决策树是一种树形结构的分类模型,它通过将数据集划分为多个子集,最终将数据分类。每个节点代表一个特征的条件,边代表特征值的取值,叶子节点代表类别标签。

  • 特点:

    • 易于理解和解释。
    • 可以处理数值型和类别型数据。
    • 对噪声数据和不平衡数据敏感。
  • 工作原理:

    • 决策树通过递归地选择最佳的特征来分割数据,使得每个分支尽可能纯(即数据类别单一)。
    • 使用某些标准(如信息增益、基尼指数)来选择最优的特征。
    • 树的构建会一直持续到所有数据被正确分类,或者达到停止条件(如最大深度、最小样本数等)。
  • 优点:

    • 可解释性强,容易理解。
    • 不需要特征缩放。
  • 缺点:

    • 容易过拟合,尤其是树很深时。
    • 对数据中小的变化非常敏感。
python 复制代码
from sklearn.tree import DecisionTreeClassifier

dtc = DecisionTreeClassifier()
dtc.fit(train_image,train_label)
predict = dtc.predict(test_image)
print("accuracy_score: %.4lf" % accuracy_score(predict,test_label))
print("Classification report for classifier %s:\n%s\n" % (dtc, classification_report(test_label, predict)))
4. Random Forest(随机森林)
  • 概念:

    随机森林是一种集成学习方法,它通过构建多棵决策树并将其结果进行投票或平均,从而得到更稳健的分类结果。每棵树都是在不同的随机子集上训练出来的。

  • 特点:

    • 通过集成多个决策树来降低过拟合的风险。
    • 可以处理大规模数据,具有较好的性能。
    • 在很多应用中效果优异。
  • 工作原理:

    • 随机选择数据的子集来训练每一棵树(Bootstrap Aggregating,简称 Bagging)。
    • 每棵树在训练时只考虑特征的一个随机子集,这进一步增加了随机性并减少了过拟合。
  • 优点:

    • 非常强大的分类器,通常比单一的决策树更准确。
    • 处理高维数据时也表现良好。
    • 对噪声不敏感。
  • 缺点:

    • 模型较复杂,较难解释。
    • 训练和预测时计算开销较大。
python 复制代码
from sklearn.ensemble import RandomForestClassifier

rfc = RandomForestClassifier()
rfc.fit(train_image,train_label)
predict = rfc.predict(test_image)
print("accuracy_score: %.4lf" % accuracy_score(predict,test_label))
print("Classification report for classifier %s:\n%s\n" % (rfc, classification_report(test_label, predict)))
5. Logistic Regression(逻辑回归)
  • 概念:

    逻辑回归是一种广泛使用的分类算法,尽管它的名字中有"回归",但它实际上是一种分类方法。它通过学习特征与类别之间的关系,输出一个类别的概率值。

  • 特点:

    • 用于二分类问题(也可以扩展到多分类问题)。
    • 模型简单,计算效率高。
    • 输出概率值,适合进行概率预测。
  • 工作原理:

    • 假设特征和类别之间存在线性关系,通过 Sigmoid 函数将线性组合映射到 0 到 1 之间。
    • 目标是最小化损失函数(如交叉熵),找到最佳的回归系数。
  • 公式:

    P(y=1∣X)=11+e−(wTX+b)P(y=1∣X)=1+e−(wTX+b)1

    其中,XX 是特征向量,ww 是模型权重,bb 是偏置项,yy 是类别。

  • 优点:

    • 输出类别概率,适合概率预测。
    • 训练速度快,且容易理解。
  • 缺点:

    • 仅适用于线性可分问题,对于非线性问题性能较差。
python 复制代码
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
lr.fit(train_image,train_label)
predict = lr.predict(test_image)
print("accuracy_score: %.4lf" % accuracy_score(predict,test_label))
print("Classification report for classifier %s:\n%s\n" % (lr, classification_report(test_label, predict)))
6. Support Vector Machine (SVM)
  • 概念:

    支持向量机(SVM)是一种基于最大间隔分类的算法。它通过在特征空间中找到一个超平面来分隔不同类别的数据点,并尽可能最大化分类边界(即最大化类别之间的间隔)。

  • 特点:

    • 强大的分类能力,尤其在高维空间中表现良好。
    • 适用于线性可分和非线性可分的情况(通过核技巧)。
    • 对于小样本数据集有较好的表现。
  • 工作原理:

    • SVM 试图找到一个超平面,使得数据点到超平面的距离尽可能大(即最大化间隔)。这种超平面被称为最优超平面
    • 核技巧(Kernel Trick)可以将数据映射到更高维的空间,使得非线性可分问题转化为线性可分问题。
  • 优点:

    • 在高维空间中依然有效。
    • 能够处理线性和非线性问题。
    • 强大的分类性能,尤其是在数据量较少时。
  • 缺点:

    • 训练速度较慢,尤其是在大规模数据集上。
    • 对于大数据集的处理较为困难。
python 复制代码
from sklearn.svm import SVC

svc = SVC()
svc.fit(train_image,train_label)
predict = svc.predict(test_image)
print("accuracy_score: %.4lf" % accuracy_score(predict,test_label))
print("Classification report for classifier %s:\n%s\n" % (svc, classification_report(test_label, predict)))
相关推荐
MoRanzhi120320 分钟前
亲和传播聚类算法应用(Affinity Propagation)
人工智能·python·机器学习·数学建模·scikit-learn·聚类
金融OG21 分钟前
99.23 金融难点通俗解释:小卖部经营比喻PPI(生产者物价指数)vsCPI(消费者物价指数)
人工智能·python·机器学习·数学建模·金融·数据可视化
艾醒(AiXing-w)33 分钟前
玩转大语言模型——使用langchain和Ollama本地部署大语言模型
人工智能·语言模型·langchain
我的青春不太冷1 小时前
2025年最新在线模型转换工具优化模型ncnn,mnn,tengine,onnx
人工智能·深度学习·ncnn·mnn·在线模型转换网址
云卷云舒___________1 小时前
【B站保姆级视频教程:Jetson配置YOLOv11环境(六)PyTorch&Torchvision安装】
人工智能·pytorch·yolo·教程·jetson·torchvision
zxfeng~1 小时前
深度学习之“线性代数”
人工智能·python·深度学习·线性代数
油泼辣子多加1 小时前
Diffusion--人工智能领域的革命性技术
人工智能
东锋1.32 小时前
NVIDIA (英伟达)的 GPU 产品应用领域
人工智能
小众AI5 小时前
AI-on-the-edge-device - 将“旧”设备接入智能世界
人工智能·开源·ai编程