0 数据说明
手写识别也是一个非常经典的应用实例。在本次应用当中,数据的格式如下:
- File name:‘_’为划分,前为标签,后为例子数。例如‘0_0’就是0的手写体的第一个实例。
- 内容:文本内容为32×32 的1-0像素存储的点,如果使用img可视化,可以看到黑白的数字的效果。待会需要处理成1*1024矩阵的形式。
1 数据处理
这一步需要比较注意的点是:
- 使用readline()方法读取的 lineStr = fr.readline(),是字符串格式的,因此在后续填充中,使用下标的形式而不是进行整体填充
- 时刻注意数据类型 如我们需要的是数字类型就绝不能放一个str
from numpy import *
from KNN import classify0
from os import listdir #用于获取当前目录下的所有文件名
#读取一个像素进制文件并将其转化为1*1024矩阵的函数方法
def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline() #读取一行,读取出来的格式是str
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j]) #填充,注意单位的转换
return returnVect
2 应用实例
代码描述:
- 使用os库中的lisdir读取训练文件夹下的所有文件名,存储,进行加工。分离。主要是将文件名字符串根据相应的特性进行分离。
- 将文件中的内容放到训练库中
- 对于测试集,也执行相似的操作,并使用之前写好的KNN.classify0分类器进行测试。返回结果和答案。
提取(下面其实有两步笔者认为可以合成一步,如果有兴趣的话大家可以试一试)
def handwritingClassTest():
hwLabels = [] #存储lable用的list
path="C:\\Users\\70956\\Desktop\\Data Science\\Algorithm"
trainingFileList = listdir(path+'\\trainingDigits') #获取所有的文件的名字
m = len(trainingFileList) #一共有多少个训练实例
trainingMat = zeros((m,1024)) #建立训练矩阵
for i in range(m): #填充,获取完整的训练数据
fileNameStr = trainingFileList[i] #获取一个名字
fileStr = fileNameStr.split('.')[0] #去掉后缀txt 保留前方名字
classNumStr = int(fileStr.split('_')[0]) #去掉_后缀,保留分类标签
hwLabels.append(classNumStr) #标签入库
trainingMat[i,:] = img2vector(path+"\\trainingDigits\\%s" % fileNameStr) #将一个文件内的数据转换成矩阵
测试
testFileList = listdir(path+'\\testDigits') #测试数据
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] #take off .txt
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector(path+'\\testDigits\\%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print ("返回的结果是: %d, 真实的类别是: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr): errorCount += 1.0
print ("\n判定错误的总数为: %d" % errorCount)
print ("\n错误率为: %f" % (errorCount/float(mTest)))
从这个实例中,其实我们可以看到对于线性的结构来执行KNN算法时,其实计算量是非常大的:
900个测试用例,2000个距离(训练用例),每次计算需要1024个特征参与。结果是18亿次。笔者的笔记本大概需要35秒左右。
试想如果在具体的十万级别的数据,或者是维度更大,计算量可能都…
900
∗
2000
∗
1024
=
1
,
843
,
200
,
000
900*2000*1024=1,843,200,000
900∗2000∗1024=1,843,200,000
如果读者有接触过数据结构,那么可能会想到我们在学习这门课程的时候学完线性表后,也考虑过这个问题(如果你的老师有用这种引入的例子的话),因此树结构就是非常有必要。
在KNN中,我们在理论部分也提到这个问题,在应用中我们确实也会碰到这个问题。
因此,我们在下次的章节。我们尝试解释KD树(K-Dimension)结构。