1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > kNN算法实现手写数字识别(机器学习)

kNN算法实现手写数字识别(机器学习)

时间:2024-04-09 05:45:53

相关推荐

kNN算法实现手写数字识别(机器学习)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

前言一、实验步骤二、实验过程 1.收集数据:提供文本文件2.准备数据:将图像转换为测试向量3.测试算法:使用k-近邻算法识别手写数字 ​总结

前言

此时实验利用KNN算法实现手写数字识别,为了简单起见只能识别数字0到9需要识别的数字已经使用图形处理软件处理成相同的色彩和大小:宽高32像素x32像素的黑白图像,并将图像转换为文本格式。

提示:以下是本篇文章正文内容,下面案例可供参考

一、实验步骤

(1)收集数据:提供文本文件;

(2)准备数据:编写函数classify0(),将图像格式转换为分类器使用的List格式;

(3)测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的区

别在于测试样本是已经完成分类的数据,如果预测分类和实际类别不同,则标记为一个

错误。

二、使用过程

1.收集数据:提供文本文件

数据集包括两部分,一部分是训练数据集,共有1934个数据;另一部分是测试数据集,共有946个数据。两个数据集中所有命名格式是统一的,例如“3_12.txt”,表示数字5 的第12个样本,这样是为了方便提取出样本的真实标签。

2.准备数据:将图像转换为测试向量

将图像格式化处理为一个向量,把每一个32x32的二进制图像矩阵转换为1x1024的向量。编写函数img2vector,将图像转换为向量:该函数创建1X1024的Numpy数组,然后打开给定的文件,循环读出文件的前32 行,并将每行的头32个字符值存储在Numpy数组中,最后返回数据。

代码如下:

#准备数据:将图像转换为数据向量def img2vector(filename):'''将图像转换为向量:param filename: 文件目录名:return: 向量数组'''#创建向量returnVect = zeros((1,1024))#打开数据文件,读取每行内容fr = open(filename)for i in range(32):#循环读取每一行lineStr = fr.readline()for j in range(32):#将每行前32字符转成int存入向量returnVect[0,32*i+j] = int(lineStr[j])return returnVect

测试img2vector函数:

testVector = img2vector("digits/testDigits/0_13.txt")print(testVector[0,0:31])print(testVector[0, 32:63])

3.测试算法:使用k-近邻算法识别手写数字

编写handwritingClassTest()函数。

代码如下:

#手写数字识别系统测试代码def handwritingClassTest():#样本数据的类标签列表hwLabels = []#样本数据文件列表trainingFileList = os.listdir("digits/trainingDigits")#得到文件行数m = len(trainingFileList)#初始化样本数据矩阵trainingMat = zeros((m,1024))#依次读取所有样本数据到数据矩阵for i in range(m):#提取文件名中的数字fileNameStr = trainingFileList[i]#去掉.txtfileStr = fileNameStr.split('.')[0]#获取第一个字符,即它是哪一个数字classNumStr = int(fileStr.split('_')[0])#保存标签hwLabels.append(classNumStr)#将样本数据存入矩阵trainingMat[i,:] = img2vector('digits/trainingDigits/%s' %(fileNameStr))#读取测试数据testFileList = os.listdir('digits/testDigits')#初始化错误率errorCount = 0.0mTest = len(testFileList)errfile = []#循环测试每个测试数据文件for i in range(mTest):fileNameStr = testFileList[i]fileStr = fileNameStr.split('.')[0]classNumStr = int(fileStr.split('_')[0])#提取数据向量vectorUnderTest = img2vector('digits/testDigits/%s' %(fileNameStr))#对数据文件进行分类classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels ,3) #传值k=3#输出k-近邻算法分类结果和真实的分类print('the classifier came back with: %d,the real answer is:%d' %(classifierResult,classNumStr))#判断k-近邻算法是否准确if(classifierResult != classNumStr):errorCount +=1.0errfile.append(fileNameStr)print('\n the total number of errors is: %d' %(errorCount))#错误的总数print('错误的是:%s ;' %[i for i in errfile])print('\n the total error rate is: %f' %(errorCount/float(mTest))) #总错误率

将trainingDigits目录中的文件内容存储在列表中,然后可以得到目录中有多少文件,并将其存储在变量m中。接着创建一个m行1024列的训练矩阵,该矩阵的每行数据存储一个图像。我们可以从文件名中解析出分类数字。如9_45.txt的分类是9,它是数字9 的第45个实例。然后我们可以将类代码存储在hwLabels向量中,使用img2vector函数载入图像。接着对testDigits目录中的文件执行相似的操作,不同之处是我们并不将这个目录下的文件载入矩阵中,而是使用classify0()函数测试该目录下的每个文件。

测试handwritingClassTest()函数:

#开始时间start = time.perf_counter()#测试handwritingClassTest()的输出结果handwritingClassTest()end = time.perf_counter()print("运行耗时:%ds" %(end-start))

测试结果:

当K=3时,测试946个数字准确率达到98.94%,只有10个数字预测错误,准确率很高,但是运行效率比较低,达到24秒。因为每个测试数据都要与1934个训练数据进行距离计算,而每次计算又包含1024个维度浮点运算,高次数多维度的计算是导致该实验运行效率低的主要原因。

将K=3改为K=5验证准确率:

K变成5之后错误率升高到1.8%,所以相对K=3是比较合适的。

选择较小的K值,就相当于用较小的领域中的训练实例进行预测,近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,K值的减小就意味着整体模型变得复杂,容易发生过拟合;选择较大的K值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单,容易欠拟合。

在实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是把训练数据在分成两组:训练集和验证集)来选择最优的K值。

在测试样本集中抽取出10个数据进行再验证:

结果如下:

10个测试结果错误两个,观察预测错误的文本文件如下:

5_1.txt预测为3,实际结果为5.

由此可以认为准备数据十分重要,同样将图像数据转换为文本数据的函数实现准确率对用K近邻算法实现手写数字识别也是必不可少的。

该处使用的url网络请求的数据。

总结

K-近邻算法:

优点:1.简单有效的分类算法,一种lazy-learningsuanfa;

2.不需要训练,训练时间复杂度为0;

3.对异常值不敏感(个别噪音数据对结果的影响不是很大)。

缺点:1.计算复杂度高,空间复杂度高,KNN算法的计算复杂度和训练集中的文档数目成正比,若

总数为N,则分类时间复杂度为O(N)。

2.耗内存:必须保存全部的数据集;

3.耗时间,运行效率比较低;

4.无法给出任何数据的内在含义。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。