利用PCA+KNN在MNIST数据集上达到97%准确率

利用PCA+KNN在MNIST数据集上达到97%准确率

  • 写在前面
  • 算法实现
    • 1、引用必要的库文件
    • 2、读入数据
    • 3、利用主成分分析对数据进行降维
    • 4、KNN的实现
    • 5、结果测试

写在前面

  1. 本文的工作基于python,利用主成分分析(PCA)和K近邻算法(KNN)在MNIST手写数据集上进行了分类。
  2. 由于skeleton库中的PCA写的很好(好吧,其实是作者很懒),本文的主成分分析(PCA)部分调用了skeleton库中的函数,所以来看PCA具体实现细节的小伙伴可能要失望了。
  3. 经过PCA降维,最终的KNN在100维的特征空间实现了超过97%的分类精度。
  4. 相信看到这篇博客的读者对于PCA和KNN的原理都比较了解了,很多大佬们也讲了很多,所以PCA和KNN的具体原理就不再啰嗦,话不多说,直接上代码。

算法实现

1、引用必要的库文件

import numpy as np
import struct
from sklearn.decomposition import PCA
from keras.datasets import mnist

为了方便,这里我们使用的MNIST数据集来自keras内置的keras.datasets,当然也可以去Yann Lecun的官网下载,只需要在之后的代码中稍加改动。

2、读入数据

我们从keras内置的数据集中读取MNIST数据集,从下面一段代码的运行结果可以看出,我们导入的MNIST数据集共有60000个训练图片和10000个测试图片,每张图片均为28*28的大小。

(train_data_ori, train_label), (test_data_ori, test_label) = mnist.load_data()
print ("mnist data loaded")
print ("original training data shape:",train_data_ori.shape)
print ("original testing data shape:",test_data_ori.shape)

附上这段代码的运行结果:

mnist data loaded
original training data shape: (60000, 28, 28)
original testing data shape: (10000, 28, 28)

显然,这里我们得到的图片是28*28的二维数组,为了方便接下来的操作,我们将每张图片reshape为一维数组:

train_data=train_data_ori.reshape(60000,784)
test_data=test_data_ori.reshape(10000,784)
print ("training data shape after reshape:",train_data.shape)
print ("testing data shape after reshape:",test_data.shape)

附上这段代码的运行结果:

training data shape after reshape: (60000, 784) testing data shape
after reshape: (10000, 784)

可以看出所有的数据图片都变成了大小为784的一维数组。

3、利用主成分分析对数据进行降维

在这里,降维的主要原因是在原有数据的784维特征空间内进行KNN聚类的计算开销过大,并且没有必要。因此,我们可以采用PCA算法提取出原有数据的主要特征。在这里,我提取了原有图片的100个主要特征,并构建了100维的特征空间。这一部分的代码如下:

pca = PCA(n_components = 100)
pca.fit(train_data) #fit PCA with training data instead of the whole dataset
train_data_pca = pca.transform(train_data)
test_data_pca = pca.transform(test_data)
print("PCA completed with 100 components")
print ("training data shape after PCA:",train_data_pca.shape)
print ("testing data shape after PCA:",test_data_pca.shape)

附上运行结果:

PCA completed with 100 components
training data shape after PCA: (60000, 100)
testing data shape after PCA: (10000, 100)

从上面的结果,我们可以分析出经过处理的数据集有着如下特点:

  1. 有60000个训练数据和10000个测试数据
  2. 所有数据的特征空间维度为100。

到这一步为止,我们已经将用于训练和测试的所有数据全部处理好。

4、KNN的实现

实现KNN的代码如下所示,其中,test_data1是待聚类的数据(1维,大小:100),train_data_pca表示的是整个训练集(2维,大小:60000*100),train_label是训练集内数据对应的标签(2维,大小:60000*1),k是KNN的参数K的值,p则表示计算距离所使用的范数类型(通常我们计算的是欧几里得距离,取2)。
该函数返回值为聚类结果。

def KNN(test_data1,train_data_pca,train_label,k,p):
    subMat = train_data_pca - np.tile(test_data1,(60000,1))
    subMat = np.abs(subMat)
    distance = subMat**p
    distance = np.sum(distance,axis=1)
    distance = distance**(1.0/p)
    distanceIndex = np.argsort(distance)
    classCount = [0,0,0,0,0,0,0,0,0,0]
    for i in range(k):
        label = train_label[distanceIndex[i]]
        classCount[label] = classCount[label] + 1    
    return np.argmax(classCount)

5、结果测试

定义测试函数如下,其中参数k为KNN算法的K值,p表示范数类型。
函数返回准确度和混淆矩阵。

def test(k,p):
    print("testing with K= %d and lp norm p=%d"%(k,p))
    m,n = np.shape(test_data_pca)
    correctCount = 0
    M = np.zeros((10,10),int)
    for i in range(m):
        test_data1 = test_data_pca[i,:]
        predict_label = KNN(test_data1,train_data_pca,train_label, k, p)
        true_label = test_label[i]
        M[true_label][predict_label] += 1
#        print("predict:%d,true:%d" % (predict_label,true_label)) use this line for debugging
        if true_label == predict_label:
           correctCount += 1
                  
    print("The accuracy is: %f" % (float(correctCount)/m))
    print("Confusion matrix:",M)

在我们测试的过程中,使用k=3和欧几里得距离,如下:

test(3,2)

得到结果:

testing with K= 3 and lp norm p=2
The accuracy is: 0.973500
Confusion matrix: [[ 974 1 1 0 0 1 2 1 0 0]
[ 0 1131 3 0 0 0 1 0 0 0]
[ 7 4 1004 1 1 0 0 13 2 0]
[ 1 1 4 979 1 9 0 7 5 3]
[ 2 5 0 0 949 0 4 3 0 19]
[ 4 1 0 10 2 865 3 1 2 4]
[ 4 3 0 0 2 4 945 0 0 0]
[ 0 17 6 0 2 0 0 996 0 7]
[ 5 1 4 17 5 10 5 3 921 3]
[ 5 5 2 8 8 2 1 6 1 971]]

最终得到了超过97%的准确率,并且我们还可以根据混淆矩阵分析出一些其他有意思的结论。

代码同时也可以在我的github上面找到,顺便求一波star^_^。

你可能感兴趣的:(利用PCA+KNN在MNIST数据集上达到97%准确率)