• 基于K-近邻分类算法的手写识别系统


    前言

           本文将继续讲解K-近邻算法的项目实例 - 手写识别系统。

           该系统在获取用户的手写输入后,判断用户写的是什么。

           为了突出核心,简化细节,本示例系统中的输入为32x32矩阵,分类结果也均为数字。但对于汉字或者别的分类情形原理都是一样的。

           有了前面学习的基础,下面直接进入项目开发步骤。

    第一步:收集并准备数据

           在用户主目录的trainingDigits子目录中,存放的是2000个样本数据。

           每个样本一个文件,其中一部分如下所示:

           

           文件命名格式为:

                  分类标签_标签内序号

           如 0_20.txt 就表示该样本是分类标签为0的第20个特征集。20就是个序号以区分标签内不同文件而已,没其他意义。

           样本数据都是32x32矩阵:

           

           对于这样的二维数据,如何判断样本和目标对象的距离呢?首先想到的是可以将二维降到一维。

           当然也可以考虑去找找二维的距离求解方法。

           下面给出降维函数:

    复制代码
     1 # ==============================================
     2 # 输入:
     3 #        训练集文件名(含路径)
     4 # 输出:
     5 #        降维后的样本数据(这里一个文件一份样本数据)
     6 # ==============================================
     7 def img2vector(filename):
     8     '将32x32的矩阵转换为1024一维向量'
     9     
    10     # 初始化返回向量
    11     returnVect = numpy.zeros((1,1024))
    12     
    13     # 打开样本数据文件
    14     fr = open(filename)
    15     
    16     # 降维处理
    17     for i in range(32):
    18         lineStr = fr.readline()
    19         for j in range(32):
    20             returnVect[0,32*i+j] = int(lineStr[j])
    21             
    22     return returnVect
    复制代码

    第二步:测试算法

           K临近的分类函数代码在之前的文章K-近邻分类算法原理分析与代码实现中给出了,这里直接调用:

    复制代码
    # =================================================
    # 输入:
    #        空
    # 输出:
    #        对指定的测试集文件,指定的训练集数据进行K近邻分类
    #        并打印结果信息
    # =================================================
    def handwritingClassTest():
        '手写数字识别系统测试代码'
        
        # 分类列表
        hwLabels = []
        
        # 获取所有训练集文件名
        trainingFileList = os.listdir('/home/fangmeng/trainingDigits')
        
        # 定义训练集结构体
        m = len(trainingFileList)
        trainingMat = numpy.zeros((m, 1024))
        
        for i in range(m):
            # 当前训练集文件名
            filenameStr = trainingFileList[i]
            # 文件名(filenameStr去掉.txt后缀)
            fileStr = filenameStr.split('.')[0]
            # 分类标签
            classNumStr = int(fileStr.split('_')[0])
            # 将分类标签加入分类列表
            hwLabels.append(classNumStr)
            # 将当前训练集文件降维后加入到训练集结构体
            trainingMat[i] = img2vector('/home/fangmeng/trainingDigits/%s' % filenameStr)
        
        # 获取所有测试集文件名
        testFileList = os.listdir('/home/fangmeng/testDigits')
        # 错误分类记数
        errorCount = 0
        # 测试集文件个数
        mTest = len(testFileList)
        
        print "错误的分类结果如下:"
        for i in range(mTest):
            # 当前测试集文件名
            fileNameStr = testFileList[i]
            # 文件名(filenameStr去掉.txt后缀)
            fileStr = fileNameStr.split('.')[0]
            # 分类标签
            classNumStr = int(fileStr.split('_')[0])
            # 将当前测试集文件降维
            vectorUnderTest = img2vector('/home/fangmeng/testDigits/%s' % fileNameStr)
            # 对当前测试文件进行分类
            classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
            
            if (classifierResult != classNumStr): 
                print "分类结果: %d, 实际结果: %d" % (classifierResult, classNumStr)
                errorCount += 1.0
                
        print "
    总错误数: %d" % errorCount
        print "
    总错误数: %f" % (errorCount/float(mTest))
    复制代码

           运行结果:

           

    小结

    1. K-邻近算法的本质是用来分类的,要从分类的思想去思考这个算法的运用。

    2. 再强调一次K-邻近算法是没有训练过程的,这点和以后学习的其他分类方法,比如决策树对比后就更清楚了。

    3. K-邻近算法的效率很低,不论是从时间还是空间上看(单就这个简单项目都跑得很慢)。因此需要学习更多更优化的算法。

    4. 有兴趣有时间可以考虑在hadoop/spark集群下实现这个项目或使用该算法的其他类似项目,定能大幅度提升性能。

  • 相关阅读:
    枚举和字符串之间的转换 [转帖]
    escape,encodeURI,encodeURIComponent函数比较[转帖]
    .net中的Provider模式 [转帖]
    ogg转到mp3
    四季养生(樊正伦教授)
    JavaScript高阶之路
    Python初识
    理解error和exception之间的区别(转)
    一些有用的话
    《爱在雨季》片尾曲
  • 原文地址:https://www.cnblogs.com/fujian-code/p/7529009.html
Copyright © 2020-2023  润新知