【机器学习】【监督学习】【算法01-实例03】K近邻(k-nearest neighbor)-手写识别

0 数据说明

手写识别也是一个非常经典的应用实例。在本次应用当中,数据的格式如下:

  • File name:‘_’为划分,前为标签,后为例子数。例如‘0_0’就是0的手写体的第一个实例。
  • 内容:文本内容为32×32 的1-0像素存储的点,如果使用img可视化,可以看到黑白的数字的效果。待会需要处理成1*1024矩阵的形式。

1 数据处理

这一步需要比较注意的点是:

  1. 使用readline()方法读取的 lineStr = fr.readline(),是字符串格式的,因此在后续填充中,使用下标的形式而不是进行整体填充
  2. 时刻注意数据类型 如我们需要的是数字类型就绝不能放一个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 应用实例

代码描述:

  1. 使用os库中的lisdir读取训练文件夹下的所有文件名,存储,进行加工。分离。主要是将文件名字符串根据相应的特性进行分离。
  2. 将文件中的内容放到训练库中
  3. 对于测试集,也执行相似的操作,并使用之前写好的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秒左右。
试想如果在具体的十万级别的数据,或者是维度更大,计算量可能都…
90020001024=1,843,200,000900*2000*1024=1,843,200,000‬
如果读者有接触过数据结构,那么可能会想到我们在学习这门课程的时候学完线性表后,也考虑过这个问题(如果你的老师有用这种引入的例子的话),因此树结构就是非常有必要。
在KNN中,我们在理论部分也提到这个问题,在应用中我们确实也会碰到这个问题。
因此,我们在下次的章节。我们尝试解释KD树(K-Dimension)结构。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章