使用k-近邻算法识别手写数字。
2018-01-06 17:37
357 查看
在之前的文章中介绍了k-近邻算法的原理知识并且用Python实现了一个分类器,而且完成了一个简单的优化约会网站配对效果的实例。在《机器学习实战》中有关kNN的后一部分内容就是一个手写识别系统,可以识别手写的0-9的数字。下面就基于这一章的内容完成这样一个手写数字识别系统。
比如其中的0_0.txt就是数字0的第一个样本,又比如9_45.txt就是数字9的第45个实例,数字样本采用的是32*32文本存储方式:
比如:0_0.txt,从图中也能看出来像数字0。
但是提供的有些数据集并不是日常所见的数字写法,比如数字7:
由于我们后续需要计算的距离就是根据这些0和1的排列方式计算的,所以类似数字7这种写法差异的话,最后分类结果也可能有差异。如果可能的话,自己也是可以根据自己的书写习惯写样本集,然后将其转换为32*32文本存放,这样一来分类结果肯定要比这种的好一点。
至于如何将图片转换为32*32数组,可以参考之前的文章:手写数字图片二值化转换为32*32数组。
在本次案例中kNN算法的使用流程:
收集数据:提供文本文件。
准备数据:自己提供的32*32数组。
分析数据:查看数据,确保符合要求。
训练算法:此步骤不适用于k-近邻算法。
测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的区别在于测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
使用算法:将一个图片作为输入数据,然后使用分类器进行分类得到结果。
编写一个简单的测试代码:
首先将0_13.txt作为参数传入img2vector函数中,然后使用len计算结果的长度是不是1*1024的,然后输出第一行内容,输出结果:
其中输出的testVector[0, 0:31]就是0_13.txt的第一行内容,可以打开0_13.txt查看对比一下:
能够看到结果一致,依此论推,testVector[0, 32:63]就是第二行的内容等等,所以确实是将0_13.txt的32*32数组转换为了1*1024向量数组。
我们先来测试一下这个算法,编写一个handwritingClassTest函数,该函数将trainingDigits目录下的所有样本进行读取,然后创建一个m*1024的训练矩阵进行存储,很显然该矩阵每一行都代表着一个图像。然后再读取testDigits目录下的测试样本集,每次读取一个文件,也就代表着一个图像,然后将其转换为1*1024数组,和原来的训练矩阵共同输入到之前的kNN分类器中进行分类。分类器会计算这个测试样本集和训练矩阵的距离,根据欧氏距离的计算方法,这个测试数据共计算m次距离,然后找到距离最近的,这个计算量还是比较巨大的。
编写一个测试代码执行这个函数:
查看一下输出结果:
可以看到错误率大概为1.2%,其实这些都是根据计算得到的结果,如果我们修改分类器k的值,或者选取不同的测试样本或者训练样本,都会影响这个错误率,不过可以看到这些训练样本集的正确率已经很高了,我们现在就可以真正的使用分类器进行识别了。
编写测试代码:
准备手写数字:
运行分类器得到结果:
能够看到识别出了数字,但是能够正确识别的关键点在于能否准确的将图片转换为32*32数组。因为使用的图片转换为32*32数组是本人简单写的一个程序,在转换过程中可能会出现问题导致分类结果不准确,如果能够用其他办法准确的将图片转换为32*32数组的话,这个分类器还是比较准确的。
全部代码及数据集地址:MachineLearningNote
案例的描述以及流程介绍。
既然我们明白了kNN算法是根据计算新数据和样本数据集之间的距离,然后找到距离最小的样本的分类作为新数据的分类。所以我们也需要考虑如何计算0-9之间这十个数字的距离。首先书中已经提供了0-9数字的样本集,每个数字提供了大概200左右的样本,在trainingDigits目录下。比如其中的0_0.txt就是数字0的第一个样本,又比如9_45.txt就是数字9的第45个实例,数字样本采用的是32*32文本存储方式:
比如:0_0.txt,从图中也能看出来像数字0。
但是提供的有些数据集并不是日常所见的数字写法,比如数字7:
由于我们后续需要计算的距离就是根据这些0和1的排列方式计算的,所以类似数字7这种写法差异的话,最后分类结果也可能有差异。如果可能的话,自己也是可以根据自己的书写习惯写样本集,然后将其转换为32*32文本存放,这样一来分类结果肯定要比这种的好一点。
至于如何将图片转换为32*32数组,可以参考之前的文章:手写数字图片二值化转换为32*32数组。
在本次案例中kNN算法的使用流程:
收集数据:提供文本文件。
准备数据:自己提供的32*32数组。
分析数据:查看数据,确保符合要求。
训练算法:此步骤不适用于k-近邻算法。
测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的区别在于测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
使用算法:将一个图片作为输入数据,然后使用分类器进行分类得到结果。
准备数据:将图像转换为测试向量。
上面已经介绍了本次的样本集是一个32*32的数组,为了使用前面的分类器,我们必须将这个32*32的数组转换为一个1*1024的向量。首先编写一个img2vector的函数,传入一个样本数据的文件名,可以将这个文件中的32*32数组转换为一个1*1024的向量。def img2vector(filename): """ 将32*32的图像矩阵转化为1*1024的向量 :param filename: 文件名 :return: """ # 制造一个空数组 returnVect = np.zeros((1,1024)) # 打开文件 fr = open(filename) # 将矩阵转换为1*1024的 for i in range(32): # 读取一行数据 lineStr = fr.readline().strip() # 将每行的数字存放在数组中 for j in range(32): returnVect[0, 32*i+j] = int(lineStr[j]) return returnVect
编写一个简单的测试代码:
首先将0_13.txt作为参数传入img2vector函数中,然后使用len计算结果的长度是不是1*1024的,然后输出第一行内容,输出结果:
其中输出的testVector[0, 0:31]就是0_13.txt的第一行内容,可以打开0_13.txt查看对比一下:
能够看到结果一致,依此论推,testVector[0, 32:63]就是第二行的内容等等,所以确实是将0_13.txt的32*32数组转换为了1*1024向量数组。
测试算法:使用k-近邻算法识别手写数字。
我们在上一步中将32*32数组转化为1*1024向量数组的目的就是为了能够使用之前编写的kNN分类器。现在就可以将样本数据集输入到分类器中进行使用了。我们先来测试一下这个算法,编写一个handwritingClassTest函数,该函数将trainingDigits目录下的所有样本进行读取,然后创建一个m*1024的训练矩阵进行存储,很显然该矩阵每一行都代表着一个图像。然后再读取testDigits目录下的测试样本集,每次读取一个文件,也就代表着一个图像,然后将其转换为1*1024数组,和原来的训练矩阵共同输入到之前的kNN分类器中进行分类。分类器会计算这个测试样本集和训练矩阵的距离,根据欧氏距离的计算方法,这个测试数据共计算m次距离,然后找到距离最近的,这个计算量还是比较巨大的。
def handwritingClassTest(): """ 数字测试 :return: """ # 数字对应的标签,也就是数字的本身 hwLabels = [] # 得到目录下的所有文件名称 trainingFileList = listdir('trainingDigits') # 计算共有多少个文件 m = len(trainingFileList) # 构造m*1024 数组,用来存放所有的数字 trainingMat = np.zeros((m, 1024)) # 遍历所有的文件,将其加载到数组中 for i in range(m): # 得到文件名称 fileNameStr = trainingFileList[i] # 去除后面的.txt,得到有用的文件名 fileStr = fileNameStr.split('.')[0] # 解析出来当前是哪个数字 classNumStr = int(fileStr.split('_')[0]) # 添加到标签上 hwLabels.append(classNumStr) # 将文件转化为数组并存放到总的数组中 trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr) # 得到测试文件的目录 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 = kNN.classify0(vectorUnderTest, trainingMat, hwLabels, 3) # 打印结果 print('使用分类器得到的结果为:%s,真实的结果为:%s' % (classifierResult, classNumStr)) # 错误的话记录下来 if classifierResult != classNumStr: errorCount += 1.0 print('识别错误的个数为:%s' % errorCount) print('分类器的正确率为:%f' % (errorCount/float(mTest)))
编写一个测试代码执行这个函数:
查看一下输出结果:
可以看到错误率大概为1.2%,其实这些都是根据计算得到的结果,如果我们修改分类器k的值,或者选取不同的测试样本或者训练样本,都会影响这个错误率,不过可以看到这些训练样本集的正确率已经很高了,我们现在就可以真正的使用分类器进行识别了。
使用算法:将手写数字图片进行识别。
在测试完分类器之后,我们就可以使用了。最终我们的目的就是输入一个自己手写的数字图片,然后分类器告诉我这个数字是几。编写classifyHandwriting函数来使用完整的系统,该函数需要一个图像名称参数,然后会将这个图像转换为32*32数组,接下来转换为1*1024数组,在读取训练样本集,然后将新数据和训练样本集共同输入到分类器中得到分类结果。def classifyHandwriting(filename): """ 将图片转化为01矩阵,然后使用分类器进行分类 :return: """ # 得到32*32的01数组 imgTo01.picTo01(filename) # 得到对应名称的txt文件 name01 = filename.split('.')[0] name01 = name01 + '.txt' # 将文件中的32*32 转化为1*1024的 hwMat = img2vector(name01) # 数字对应的标签,也就是数字的本身 hwLabels = [] # 得到目录下的所有文件名称 trainingFileList = listdir('trainingDigits') # 计算共有多少个文件 m = len(trainingFileList) # 构造m*1024 数组,用来存放所有的数字 trainingMat = np.zeros((m, 1024)) # 遍历所有的文件,将其加载到数组中 for i in range(m): # 得到文件名称 fileNameStr = trainingFileList[i] # 去除后面的.txt,得到有用的文件名 fileStr = fileNameStr.split('.')[0] # 解析出来当前是哪个数字 classNumStr = int(fileStr.split('_')[0]) # 添加到标签上 hwLabels.append(classNumStr) # 将文件转化为数组并存放到总的数组中 trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr) # 进行分类 classifierResult = kNN.classify0(hwMat, trainingMat, hwLabels, 3) print('使用分类器的结果为:%d' % classifierResult )
编写测试代码:
准备手写数字:
运行分类器得到结果:
能够看到识别出了数字,但是能够正确识别的关键点在于能否准确的将图片转换为32*32数组。因为使用的图片转换为32*32数组是本人简单写的一个程序,在转换过程中可能会出现问题导致分类结果不准确,如果能够用其他办法准确的将图片转换为32*32数组的话,这个分类器还是比较准确的。
全部代码及数据集地址:MachineLearningNote
相关文章推荐
- 机器学习实战——使用K-近邻算法识别手写数字
- 『机器学习实战』使用 k-近邻算法识别手写数字
- 使用Knn算法实现手写数字识别系统(附带jpg转txt代码)
- 使用kNN算法识别手写数字
- KNN近邻算法(python3)识别手写数字
- 基于K-近邻算法识别手写数字的实现
- 【机器学习】k-近邻算法应用之手写数字识别
- 机器学习整理笔记——使用k-近邻算法对手写识别系统的测试
- 机器学习实战之k-近邻算法(6)---手写数字识别系统(0-9识别)
- 【机器学习】k-近邻算法应用之手写数字识别
- 《机器学习实战》第二章:k-近邻算法(3)手写数字识别
- k-近邻算法实现手写数字识别
- tensorflow 学习专栏(五):在mnist数据集上使用tensorflow实现临近算法(Nearest-Neighbor)进行手写数字识别
- 基于K-近邻算法的手写数字识别研究
- k-近邻算法实现手写数字识别系统
- 使用KNN算法在python下识别手写数字(带注释)
- Python 学习笔记(Machine Learning In Action)K-近邻算法识别手写数字
- k-近邻算法实现手写数字识别系统
- 机器学习深度学习基础笔记(2)——梯度下降之手写数字识别算法实现
- 《机器学习实战二》K近邻学习之手写数字识别及检测识别错误率