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

# 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)))
相关推荐
jndingxin3 分钟前
OpenCV 图形API(63)图像结构分析和形状描述符------计算图像中非零像素的边界框函数boundingRect()
人工智能·opencv·计算机视觉
旧故新长8 分钟前
支持Function Call的本地ollama模型对比评测-》开发代理agent
人工智能·深度学习·机器学习
微学AI21 分钟前
融合注意力机制和BiGRU的电力领域发电量预测项目研究,并给出相关代码
人工智能·深度学习·自然语言处理·注意力机制·bigru
知来者逆32 分钟前
计算机视觉——速度与精度的完美结合的实时目标检测算法RF-DETR详解
图像处理·人工智能·深度学习·算法·目标检测·计算机视觉·rf-detr
一勺汤35 分钟前
YOLOv11改进-双Backbone架构:利用双backbone提高yolo11目标检测的精度
人工智能·yolo·双backbone·double backbone·yolo11 backbone·yolo 双backbone
武汉唯众智创37 分钟前
高职人工智能技术应用专业(计算机视觉方向)实训室解决方案
人工智能·计算机视觉·人工智能实训室·计算机视觉实训室·人工智能计算机视觉实训室
Johny_Zhao1 小时前
MySQL 高可用集群搭建部署
linux·人工智能·mysql·信息安全·云计算·shell·yum源·系统运维·itsm
一只可爱的小猴子1 小时前
2022李宏毅老师机器学习课程笔记
人工智能·笔记·机器学习
地瓜机器人1 小时前
乐聚机器人与地瓜机器人达成战略合作,联合发布Aelos Embodied具身智能
人工智能·机器人
带娃的IT创业者1 小时前
《AI大模型趣味实战》基于RAG向量数据库的知识库AI问答助手设计与实现
数据库·人工智能