基于Python的机器学习算法实现-K-近邻算法(三)-手写识别

基于Python的机器学习算法实现-K-近邻算法(三)-手写识别

前言

大数据集下的手写识别案例。本案例的基础是,已经将手写的图片转为标准化的32*32黑白图像,并转为txt格式的文件。测试的数据为数字0-9。其中测试数据和训练数据文件皆放在文末的百度云盘中。这里的过程与之前的很类似,这里不再赘述。

01.图片的文件展示

这里写图片描述

02.代码详解

这里依然按照之前的方式,建立一个kNN文件,并且需要导入以下包:

#导入numpy的所有函数到当前环境
from numpy import *
#运算符模块,k-近邻算法执行排序操作时使用的模块
import operator
#导入图形处理模块
import matplotlib
import matplotlib.pyplot as plt
import os
import os.path

将图形转为测试向量模块

#将图像转为测试向量,已经规定好了
def img2vector(filename):
    #生成一个1韩1024列0矩阵(32*32) 
    returnVect = zeros((1,1024))
    #打开文件读取信息
    fr = open(filename)
    for i in range(32):
        #循环读取行信息
        lineStr = fr.readline()
        #循环读取列信息
        for j in range(32):
            #列数增加,将读取的字符串拽为int类型,赋值
            returnVect[0,32*i+j] = int(lineStr[j])
    #返回标准化矩阵
    return returnVect

手写识别模块

#手写识别
def handwritingClassTest():
    #空白列表,放文件对应的数字标签
    hwLabels = []
    #获取当前目录
    trainingFileList = os.listdir('trainingDigits')           
    print(trainingFileList)
    #获取列表的长度
    m = len(trainingFileList)
    #生成一个m行1024列的0矩阵
    trainingMat = zeros((m,1024))
    #循环,将数据写到训练集数据中
    for i in range(m):
        #获取文件名称
        fileNameStr = trainingFileList[i]
        #去掉文件后缀
        fileStr = fileNameStr.split('.')[0]     
        #获取该文件的标签,即实际的数值
        classNumStr = int(fileStr.split('_')[0])
        #将标签写入到列表中
        hwLabels.append(classNumStr)
        #将该数据的内容写到对应的测试数据集中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
    #获取testDigits目录下的文件列表
    testFileList = listdir('testDigits')       
    #定义个记录预测错误的变量
    errorCount = 0.0
    #获取测集中数据的长度
    mTest = len(testFileList)
    #检测训练集的预测错误率
    for i in range(mTest):
        #获取该目录下对应文件的名称
        fileNameStr = testFileList[i]
        #获取对应文件的标签
        fileStr = fileNameStr.split('.')[0]    
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        #开始测试
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        #测试值,实际值
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0
    print("\nthe total number of errors is: %d" % errorCount)
    print("\nthe total error rate is: %f" % (errorCount/float(mTest)))

当然其中也会用到之前的模块:分类函数

分类函数,四个参数分别是:测试数据集,训练的数据集,训练数据集对应的类别,所选的最近邻近数目
def classify0(inX,dataSet,labels,k):
    #获取训练集的中的数据数量,这是二维数据中的长度
    #计算距离
    #需要注意,dataSet.shape 返回一个tuple,(a,b)就是a行b列
    dataSetSize=dataSet.shape[0]
    #tile 是numpy中的函数,这里是将inX的行复制dataSetSize次,将列复制1次;然后每个数据减去数组的训练集对应的值
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    #将数组各个元素平方
    sqDiffMat=diffMat**2
    #将矩阵sqDiffMat 每一行元素相加成为新的矩阵中对应位置中
    sqDistances=sqDiffMat.sum(axis=1)
    #对结果去平方根
    distances=sqDistances**0.5
    #对distances进行从小到大的排序,并提取对应的索引值
    sortedDistIndicies=distances.argsort()
    #定义一个空的字典类型
    classCount={}
    #选择距离最小的k个点
    #根据输入的参数的k进行循环
    for i in range(k):
        #根据索引获取对应的所属类的值
        voteIlabel=labels[sortedDistIndicies[i]]
        #向字典中添加值 其中的get 如果获取步到键为voteIlabel,就把0赋值过去然后+1
        #当第二次遇到同一个label时,0已经不起作用了,直接获取当前的值,然后+1 ,可以起记录作用,由于键值一样有数据会这覆盖
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    #将字典classCount进行排序,其参数分别是可迭代对象,key为主要用来比较的元素,operator.itemgetter(1)获取对象哪维数据,reverse=True为降序
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回距离小的标记
    return sortedClassCount[0][0]

03.运行程序

进入当前文件目录的dos,具体如下图:
这里写图片描述
由于数据量比较大,以及需要计算的比较多,计算时间长,计算的结果为如图
这里写图片描述
程序的源代码以及训练数据集和测试集:链接:https://pan.baidu.com/s/1qJAFCVho4HylUj2B-l7mIg 密码:y7o5
有兴趣的可以关注博主的个人订阅号:自然语言处理爱好者 id:NLP_lover
这里写图片描述

猜你喜欢

转载自blog.csdn.net/meiqi0538/article/details/80240342