# 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)))