# 使用KNN实现MNIST数据分类(笔记)

导入相关包

import operator
import matplotlib.pyplot as plt
import numpy as np
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

库解释:

  • operator模块:提供了许多Python内置操作符的函数形式,以及其他一些有用的函数,例如排序、查找等。
  • matplotlib.pyplot模块:提供了绘制各种图表的函数,如折线图、散点图、柱状图等。
  • numpy库:它是Python中科学计算的基础包,提供了许多高效的科学计算功能。
  • torch.utils.data模块:提供了许多用于处理数据的实用程序,如数据集、数据处理,以及数据加载工具等。
  • datasets模块:提供了许多常用的数据集,如MNIST数据集、CIFAR-10数据集等。
  • transforms模块:提供了许多数据预处理工具,如数据归一化、数据转换等。

通过torchvision中的datasetstransforms来加载训练集和测试集,并且将其转换为Tensor类型。同时指定batch_size并通过DataLoader来实现数据的加载。

batch_size = 100
train_dataset = datasets.MNIST(
    root="./data/",
    train=True,  # 表示下载的是训练集
    transform=transforms.ToTensor(),  # 将训练集中的数据转换为 Tensor 类型
    download=True)  # 在线下载

test_dataset = datasets.MNIST(
    root="./data/",
    train=False,  # 表示下载的是测试集
    transform=transforms.ToTensor(),
    download=True)


加载数据
训练集包括60000个样本,测试数据集包括10000个样本。
在MNIST数据集中,每张图片均由28 $\times$ 28的像素展开为一个一维的行向量,这些行向量就是图片数组里的行(每行784个值,或者说每行就代表了一张图片)
训练集以及测试集的标签包含了相应的目标变量,也就是手写数字的类标签

train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

图片就是比较28×28的像素块。最简单的方法就是逐个像素进行比较,最后将差异值全部相加。
两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片差别很大,那么,L1的值将会非常大。
接下来实现了KNN算法的分类函数
KNN_classify

其中,通过欧拉距离曼哈顿距离来计算测试数据和训练数据之间的距离,并选取距离最近的前k个数据进行分类,使用字典class_count来记录每个类别出现的次数,最后得到测试数据的预测标签。

def KNN_classify(k, dis, train_data, train_label, test_data):
    assert dis == 'E' or dis == 'M', 'dis must be E or M, E代表欧拉距离,M代表曼哈顿距离'
    num_test = test_data.shape[0]  # 测试样本的数量
    label_list = []
    if dis == 'E':
        # 欧拉距离的实现
        for i in range(num_test):
            distances = np.sqrt(np.sum(((train_data - np.tile(test_data[i], (train_data.shape[0], 1))) ** 2), axis=1))
            nearest_k = np.argsort(distances)
            top_k = nearest_k[:k]  # 选取前k个距离
            class_count = {}
            for j in top_k:
                class_count[train_label[j]] = class_count.get(train_label[j], 0) + 1
            sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
            label_list.append(sorted_class_count[0][0])
    else:
        # 曼哈顿距离
        for i in range(num_test):
            distances = np.sum(np.abs(train_data - np.tile(test_data[i], (train_data.shape[0], 1))), axis=1)
            nearest_k = np.argsort(distances)
            top_k = nearest_k[:k]
            class_count = {}
            for j in top_k:
                class_count[train_label[j]] = class_count.get(train_label[j], 0) + 1
            sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
            label_list.append(sorted_class_count[0][0])
    return np.array(label_list)


进行归一化处理后再进行分类
getXmean函数中,对所有训练数据的像素均值求出,用centralized函数对所有数据进行中心化处理,即将其减去均值,实现领均值化。

def getXmean(data):
    image = np.reshape(data, (data.shape[0], -1))
    #  将该三维数组转换为一个二维数组,其中每行表示一个图像的像素值。data.shape[0]表示要重新形状的数组的第一维度的长度,而-1表示我们想要numpy自动计算该数组的第二维度的长度,以使总元素数量不变。
    mean_image = np.mean(image, axis=0)  # 计算每列的平均值
    return mean_image


def centralized(data, mean_image):
    data = data.reshape((data.shape[0], -1))
    data = data.astype(np.float64)
    data -= mean_image  # 减去图像均值,实现领均值化
    return data

if __name__ == '__main__':中,将训练数据和测试数据进行数据处理和归一化,使用KNN算法进行训练和测试,最后得到测试的分类准确率。

if __name__ == '__main__':
    # 训练数据
    train_data = train_loader.dataset.data.numpy()  # 张量转换为numpy数组
    mean_image = getXmean(train_data)  # 计算所有图像均值
    train_data = centralized(train_data, mean_image)  # 对训练集图像进行均值化处理
    print(train_data.shape)
    train_label = train_loader.dataset.targets.numpy()
    print(train_label.shape)

    # 测试数据
    test_data = test_loader.dataset.data[:1000].numpy()
    test_data = centralized(test_data, mean_image)  # 对测试集数据进行均值化处理
    print(test_data.shape)
    test_label = test_loader.dataset.targets[:1000].numpy()
    print(test_label.shape)

    # 训练
    test_label_pred = KNN_classify(5, 'E', train_data, train_label, test_data)

    # 得到训练准确率
    num_test = test_data.shape[0]
    num_correct = np.sum(test_label == test_label_pred)
    print(num_correct)
    accuracy = float(num_correct) / num_test
    print('Got %d / %d correct => accuracy: %f' % (num_correct, num_test, accuracy))

运行截图:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个问题我可以帮你回答,但是需要说明的是,Isomap算法虽然可以对MNIST数据集进行降维,但是在实际应用中,通常使用更先进的降维算法,比如t-SNE算法。而对于MNIST数据集的分类KNN算法是一种简单而有效的方法,但是在实际应用中,通常使用更先进的分类算法,比如卷积神经网络等。下面是基于Isomap和KNN的手写MNIST数据集降维和分类的步骤: 1. 加载手写MNIST数据集。手写MNIST数据集包含60000个训练样本和10000个测试样本,每个样本是一个28x28的灰度图像,对应一个0到9之间的数字标签。 2. 将图像数据展开成一维向量。将每个28x28的图像展开成一个784维的向量,以便于进行降维操作。 3. 使用Isomap算法进行降维。使用Isomap算法将784维的图像向量降维到2维或3维,以便于可视化和分类操作。降维后的数据点可以用散点图进行可视化,观察不同数字之间的分布情况。 4. 使用KNN算法进行分类。将降维后的数据集划分为训练集和测试集,然后使用KNN算法对测试集中的样本进行分类KNN算法的基本思想是将测试样本的特征向量与训练集中的所有样本进行比较,选择距离最近的K个训练样本,根据这K个样本的标签来预测测试样本的标签。KNN算法的性能取决于K的选择和距离度量的选择。 需要注意的是,Isomap算法和KNN算法的具体实现需要使用相应的机器学习库,比如scikit-learn等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值