使用KNN实现MNIST数据分类(详细解释附完整程序)

数据读取

import operator
import os

import matplotlib.pyplot as plt
import numpy as np
import torchvision.datasets as dsets
from torch.utils.data import DataLoader

relative_path = os.getcwd()

batch_size = 100
train_dataset = dsets.MNIST(root=relative_path + '\pymnist',  # 选择数据的根目录
                            train=True,  # 选择训练集
                            transform=None,  # 不使用任何数据预处理
                            download=False)  # 从网络上下载图片

test_dataset = dsets.MNIST(root=relative_path + '\pymnist',  # 选择数据的根目录
                           train=False,  # 选择测试集
                           transform=None,  # 不适用任何数据预处理
                           download=False)  # 从网络上下载图片

加载数据

训练集包括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)

print("train_data:", train_dataset.data.size())
print("train_labels:", train_dataset.data.size())
print("test_data:", test_dataset.data.size())
print("test_labels:", test_dataset.data.size())

先来了解一下MNIST中的图片看起来是什么,对他进行可视化处理,通过Matplotlib的imshow函数进行绘制

digit = train_loader.dataset.data[0]  # 取第一个图片的数据
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
print(train_loader.dataset.targets[0])

在真正使用Python实现KNN算法之前,我们先来剖析一下思想,这里我们以MNIST的60000张图片作为训练集,我们希望对测试数据集的10000张图片全部打上标签。KNN算法将会比较测试图片与训练集中每一张图片,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片

那么,具体应该如何比较这两张图片呢?在本例中,比较图片就是比较28×28的像素块。最简单的方法就是逐个像素进行比较,最后将差异值全部加起来

两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片差别很大,那么,L1的值将会非常大。

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)

直接使用KNN

if __name__ == '__main__':
	# 训练数据
	train_data = train_loader.dataset.data.numpy()
	train_data = train_data.reshape(train_data.shape[0], 28 * 28)
	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 = test_data.reshape(test_data.shape[0], 28 * 28)
    print(test_data.shape)
    test_label = test_loader.dataset.targets[:1000].numpy()
    print(test_label.shape)

    # 训练
    test_label_pred = KNN_classify(5, 'M', 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))

运行结果:

image-20220129235449949

进行归一化处理后再进行分类

def getXmean(data):
    data = np.reshape(data, (data.shape[0], -1))
    mean_image = np.mean(data, 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__':
    # 训练数据
    train_data = train_loader.dataset.data.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, 'M', 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))

运行结果:

image-20220129235501874

完整程序

#!/usr/bin/env python
# coding: utf-8

# # 使用KNN实现MNIST数据分类
# ## 数据读取


import operator
import os

import matplotlib.pyplot as plt
import numpy as np
import torchvision.datasets as dsets
from torch.utils.data import DataLoader

relative_path = os.getcwd()

batch_size = 100
train_dataset = dsets.MNIST(root=relative_path + '\pymnist',  # 选择数据的根目录
                            train=True,  # 选择训练集
                            transform=None,  # 不使用任何数据预处理
                            download=False)  # 从网络上下载图片

test_dataset = dsets.MNIST(root=relative_path + '\pymnist',  # 选择数据的根目录
                           train=False,  # 选择测试集
                           transform=None,  # 不适用任何数据预处理
                           download=False)  # 从网络上下载图片

# ## 加载数据
# 训练集包括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)

print("train_data:", train_dataset.data.size())
print("train_labels:", train_dataset.data.size())
print("test_data:", test_dataset.data.size())
print("test_labels:", test_dataset.data.size())

# 先来了解一下MNIST中的图片看起来是什么,对他进行可视化处理,通过Matplotlib的imshow函数进行绘制


digit = train_loader.dataset.data[0]  # 取第一个图片的数据
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
print(train_loader.dataset.targets[0])


# 在真正使用Python实现KNN算法之前,我们先来剖析一下思想,这里我们以MNIST的60000张图片作为训练集,我们希望对测试数据集的10000张图片全部打上标签。KNN算法将会比较测试图片与训练集中每一张图片,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片
# 那么,具体应该如何比较这两张图片呢?在本例中,比较图片就是比较28×28的像素块。最简单的方法就是逐个像素进行比较,最后将差异值全部加起来
# 两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片差别很大,那么,L1的值将会非常大。


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)


if __name__ == '__main__':
    # 训练数据
    train_data = train_loader.dataset.data.numpy()
    train_data = train_data.reshape(train_data.shape[0], 28 * 28)
    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 = test_data.reshape(test_data.shape[0], 28 * 28)
    print(test_data.shape)
    test_label = test_loader.dataset.targets[:1000].numpy()
    print(test_label.shape)

    # 训练
    test_label_pred = KNN_classify(5, 'M', 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))


# 进行归一化处理后再进行分类

def getXmean(data):
    data = np.reshape(data, (data.shape[0], -1))
    mean_image = np.mean(data, 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__':
    # 训练数据
    train_data = train_loader.dataset.data.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, 'M', 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))
  • 12
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,我会尽力回答你的问题。首先,针对你的问题,我需要说明一下,我是一个AI语言模型,没有存储任何历史信息,所以我并不知道你之前对我说了什么话。不过,我可以帮助你解决问题,以下是我对你的问题的回答。 针对你的问题,我将一步一步地介绍如何使用python语言,应用Kmeans++算法,编写程序实现聚类并测试MNIST数据数据库。具体步骤如下: 一、载入数据,然后划分为训练集和测试集。 首先,我们需要从MNIST数据集中载入数据MNIST数据集是一个手写数字识别的数据集,其中包含了60000个训练样本和10000个测试样本,每个样本是一个28*28的灰度图像。你可以从官网下载MNIST数据集,也可以使用python中的keras库直接载入数据。 代码示例: ```python from keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() ``` 接下来,我们需要将数据进行预处理,将像素值缩放到0到1之间,并将28*28的图像转换为一个784维的向量。同时,我们需要将训练集和测试集进行划分,一般情况下,我们可以将70%的数据作为训练集,30%的数据作为测试集。 代码示例: ```python import numpy as np from sklearn.model_selection import train_test_split x_train = x_train.reshape(-1, 784) / 255.0 x_test = x_test.reshape(-1, 784) / 255.0 y_train = np.eye(10)[y_train] y_test = np.eye(10)[y_test] x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=0.3, random_state=2021) ``` 二、应用PCA算法对数据进行降维处理。 MNIST数据集的维度是很高的,这会导致计算量非常大,因此我们需要对数据进行降维处理。常用的降维方法有PCA和t-SNE等。这里我们使用PCA对数据进行降维。 代码示例: ```python from sklearn.decomposition import PCA pca = PCA(n_components=50) x_train_pca = pca.fit_transform(x_train) x_val_pca = pca.transform(x_val) x_test_pca = pca.transform(x_test) ``` 三、编写Kmeans++算法程序,用训练集实现聚类。 Kmeans++是一种常用的聚类算法,在处理大规模数据时效果比较好。其主要思想是选择初始聚类中心时,让它们尽可能地分散开来,避免聚类中心过于靠近或者重合。在Kmeans++算法中,将数据划分为K个簇,然后通过不断迭代,使得每个数据点与最近的聚类中心相连。最终的目标是使得所有数据点都距离最近的聚类中心最近,同时使得每个簇的内部方差最小。 代码示例: ```python from sklearn.cluster import KMeans kmeans = KMeans(n_clusters=10, init='k-means++', random_state=2021) kmeans.fit(x_train_pca) train_pred = kmeans.predict(x_train_pca) val_pred = kmeans.predict(x_val_pca) test_pred = kmeans.predict(x_test_pca) ``` 四、计算聚类的sh系数。 为了评估聚类的效果,我们可以采用sh系数来衡量聚类的紧密程度和分离程度。sh系数越大,说明聚类效果越好。 代码示例: ```python from sklearn.metrics import silhouette_score train_score = silhouette_score(x_train_pca, train_pred) val_score = silhouette_score(x_val_pca, val_pred) test_score = silhouette_score(x_test_pca, test_pred) print("Train sh score: {:.4f}, Val sh score: {:.4f}, Test sh score: {:.4f}".format(train_score, val_score, test_score)) ``` 五、用测试集进行验证(可以采用KNN算法)。 最后,我们可以使用KNN算法来对测试集进行验证。KNN算法是一种基于距离的分类算法,它的基本思想是将每个测试样本与训练集中的所有样本进行距离比较,然后将距离最近的K个样本作为该测试样本的邻居,根据邻居的标签进行分类。 代码示例: ```python from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=5) knn.fit(x_train_pca, np.argmax(y_train, axis=1)) train_acc = knn.score(x_train_pca, np.argmax(y_train, axis=1)) val_acc = knn.score(x_val_pca, np.argmax(y_val, axis=1)) test_acc = knn.score(x_test_pca, np.argmax(y_test, axis=1)) print("Train acc: {:.4f}, Val acc: {:.4f}, Test acc: {:.4f}".format(train_acc, val_acc, test_acc)) ``` 以上就是使用python语言,应用Kmeans++算法,编写程序实现聚类并测试MNIST数据数据库的完整步骤。希望我的回答能够对你有所帮助。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydrion-Qlz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值