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

# 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)))
相关推荐
手打猪大屁1 分钟前
树莓派——Opencv_python基本操作
人工智能·python·opencv·目标检测·计算机视觉
ToTensor4 分钟前
VLLM 格式化LLM输出
人工智能
学习前端的小z8 分钟前
【AI绘画】Midjourney进阶:色调详解(下)
人工智能·ai作画·aigc·midjourney
『₣λ¥√≈üĐ』10 分钟前
如何写出好证明(支持思想的深入数学写作)
人工智能·学习·数学建模·矩阵·动态规划·概率论·抽象代数
qq_3521095216 分钟前
自动驾驶目标检测融合全貌
人工智能·目标检测·自动驾驶
ZOMI酱18 分钟前
【AI系统】动态图与静态图转换
人工智能
知来者逆23 分钟前
ChemBench—— 探索大语言模型在化学领域的新基准框架是否胜过化学专家
人工智能·语言模型·自然语言处理·llm·大语言模型·化学
花生糖@36 分钟前
OpenCV截取指定图片区域
人工智能·opencv·计算机视觉
tlk李lilili1 小时前
如何选择合适的电网安全警示牌|防外破声光警示牌,确保电力设施安全
人工智能·语音识别
魍魉19881 小时前
神经网络的数学——一个完整的例子
神经网络·决策树·机器学习