版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27668313/article/details/78990432
KNN的原理可参考博客:
https://www.cnblogs.com/21207-iHome/p/6084670.html
本文采用PCA+KNN的方法进行手写数字识别,训练数据来源于kaggle,已上传到我的CSDN博客,训练数据共有42000行,每行代表一幅数字图片,共有784列(一副数字图像是28*28像素,将一副图像展开为一行即784),更多关于Digit Recognizer项目的介绍https://www.kaggle.com/c/digit-recognizer
由于训练数据量太大,直接采用KNN非常耗时,在个人PC上半小时都跑不完全部数据,采用PCA降维的方法,选取25个维度,跑完全部数据只需200秒左右。下面代码采用
python3.X,代码中的predict()可以不用管,这个是用于预测test.csv数据的。
对于PCA维度的选取:在多次尝试后,采用25个维度的精确度已能达到96%,效果较好。需要注意的是,PCA处理后的训练数据和原始数据是不同的,所以采用PCA处理数据后,并不是选取的维度越多精确度就越好。
我觉得可以这样理解,采用PCA处理后的数据,数据可以分为主要成分和次要成分,只有那些主要成分对图像的贡献度最大,次要成分可以看成是噪声。如果选取的维度太多,噪声也就多了,这样识别率就低了,实际实验中显示采用PCA后选用784维,精确度只有23%。而没有经过PCA处理的数据,每个维度的重要性都是一样的,不存在主要成分和次要成分之分(实际上原始数据还是存在次要成分的,只不过没有经过处理后,维度之间的重要性无法区分开来,经过PCA处理后,就好像把原来的数据从一个空间映射到另一个空间,在这个空间中,主要成分和次要成分就区分开来了),没有采用PCA处理数据,直接用KNN计算全部的784维,精确度接近97%。
以下是采用PCA后,尝试不同选取维度后得到的精确度。
维度数 精确度
784 23.2%
400 26.7%
300 38.1%
200 60.5%
100 85.7%
40 92.5%
30 94%
20 93.3%
10 90%
本次采用样本数:8000
原始样本数:42000
784 23.2%
400 26.7%
300 38.1%
200 60.5%
100 85.7%
40 92.5%
30 94%
20 93.3%
10 90%
本次采用样本数:8000
原始样本数:42000
import numpy as np
from numpy import *
import operator
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
import time
time_start = time.time()
def loadDataSet(filedir):
DateSet = pd.read_csv(filedir)
Data = DateSet.iloc[1:42001, 1:].as_matrix() # dataframe格式转成元组
# 降维处理
pca = PCA(n_components=25, whiten=True)
Data = pca.fit_transform(Data)
print('Data size: ', shape(Data))
label = DateSet.iloc[1:42001, :1].as_matrix()
# 分配训练数据和测试数据
train_data, test_data, train_label, test_label = train_test_split(Data, label, test_size=0.3, random_state=0)
return train_data, test_data, train_label, test_label
def kNN_classify(classify_data, train_data, train_label, k):
# 计算欧式距离
m = shape(train_data)[0]
diff = tile(classify_data, (m, 1)) - train_data
dist = sqrt(sum(diff**2, axis=1))
# print('m ', m)
data_index = argsort(dist) # 升序排序,得到索引值
# print('data_index: ', data_index)
# print('data_index: ', data_index)
# 取前k个与classify_data距离最小的训练数据的标签
data_label = []
for i in range(k):
data_label.append(train_label[data_index[i]][0])
# print('data_label: ', data_label)
# 选取数量最多的标签作为classify_data的分类标签
classify_label = {}
for j in range(k):
votelabel = data_label[j]
classify_label[votelabel] = classify_label.get(votelabel, 0) + 1
# print('classify_label: ', classify_label)
maxValue = 0
class_label = None
for label, value in classify_label.items():
if value > maxValue:
maxValue = value
class_label = label
return class_label
def train_model(train_data, test_data, train_label, test_label, k=5):
m = shape(test_data)[0]
err_num = 0
for i in range(m):
result = kNN_classify(test_data[i], train_data, train_label, k)
if result != test_label[i]:
err_num += 1
accuracy = (m - err_num)/m
return accuracy
# 这个函数可以注释掉
def predict(filedir, train_data, train_label, k):
predict_data = pd.read_csv(filedir)
predict_data = predict_data.iloc[1:100, :].as_matrix()
m = shape(predict_data)[0]
result = zeros((m, 1))
for i in range(m):
result[i] = kNN_classify(predict_data[i], train_data, train_label, k=5)
df = pd.DataFrame(result)
df.index.name = ['ImageId']
df.index += 1
df.columns = ['Label']
df.to_csv('E:\ProgramData\Python3Project\Digit Recognizer/result.csv', header=True)
print('predict done!')
filedir = 'E:\ProgramData\Python3Project\Digit Recognizer/train.csv'
train_data, test_data, train_label, test_label = loadDataSet(filedir)
accuracy = train_model(train_data, test_data, train_label, test_label, 5)
print('accuracy: %f' % accuracy)
time_end = time.time()
print('totally cost:', time_end - time_start)
print('Done')