基于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