Python3:《机器学习笔记与实战》之Knn算法(2)识别手写数字

转载请注明作者和出处:https://blog.csdn.net/weixin_41858342/article/details
代码及数据地址:https://github.com/yuankaihua668/knn-code-and-data.git
操作系统:WINDOWS 10
软件版本:python-3.6.2-amd64
编  者:一个从大山到原野的孩子
---------------------

在上一章中,我们对Knn算法的基本原理、应用场景、优缺点等做了简要总结。通过我们约会吧的算法实战,相信,大家对K近邻算法有了更深入的掌握。其实作为一个小白的我来说,同样也认为Knn是所有算法中最简单也比较实用的算法。本节,我们将用手写识别数字的实例,再深入总结Knn算法的实现框架和代码。

上一章中,我们谈到小野转入了正式的小学,开始了他的学习生涯。同学们可能在想,作者不是写代码总结算法吗?怎么写起了这些平淡的学习生活。是的,其实生活总是要归于平淡,在平淡的生活中,只要你细细回味,总能体会到人生旅途中你所经历的那些感动、真诚、奋斗、委屈、无助和孤独。但到最后,你会发现,人生就是一次旅行,无论平穷与富贵,我们所能做的无非是不忘初心,每天认真生活,不负好时光。

我们新的小学是一个近似平行四边形的布局,两面环水,东北两面环山,正中是一个约200平的小操场,靠近西面有一个摇摇欲坠的篮球架,周围有高大的柳树。靠东面有个一米高的舞台背靠田地,儿时几个小伙伴围在一起在上面抓石子(总共5颗石子,一个人算一队,也可多个人算一队,从1、2,1开始抓;其中1颗是抓之前要捡开的,抓的途中 石子落地算输,抓完后,用手背背石子,背的过程是从手心到手背再到手心。背的过程中,石子落地算输。可以约定背到多少石子算赢。比如30颗。谁先到30谁赢)的场景还历历在目。西边背靠小河,是一个长8米左右,高3米多的白色矮小的瓦房,那是我们1年级老师带着孩子们玩的地方,偶尔也会拿一间屋子放一个乒乓球台,即使在下课10分钟的时间里,6年级最有权威的同学也会拿着全校仅有的一副乒乓球牌在这打上一局,其他同学要玩就要排队,遗憾的是,排队往往从第一节课开始排到放学还没排到,为了缓解矛盾,校长就会规定一个年级用一天。

靠北的是一排有近百年历史的老的木架、木板加竹篱笆的古老房子,房瓦盖的是全镇我只在此处见过的长长的琉璃瓦,房角和房顶的瓦片还有各种鸟兽的刻图造型,从西向东延伸,越来越矮,到最东边长约15米,最矮处有两间土墙瓦屋,一间用来给附近同学蒸午饭,还开了个一米左右的小窗,方便取饭;另一间是老师们住校的地方。南面是一排白色规整的砖墙房背靠仁河,上面有同学们用各色粉笔画的小图案,和一些孩童般天真的文字,墙面原本都是干净整洁的,但到我们读书的年代,他已经历了多年的风霜,日晒雨露,如季末的花一般即刻凋零,奄奄一息。除了这些图和文字,2米以下的墙面,白色石灰装饰过的墙面已到处脱落,脱落的遍体鳞伤,有的地方快要穿孔。我所在的教室就是南面一排的最东边的那一间。小野的6年小学生涯就是在这里度过的。关于在这,所经历的印象深刻的童年趣事。将在下一章更新。先上代码……

所有代码可以在此复制也可前往我的github地址下载代码和测试数据。所有代码都是可以改文件路径后,直接运行的。其中我加了理解的注释,涉及到numpy 数组 矩阵的高级用法 还是很值得一学的。

# -*- coding: utf-8 -*-
# @Date    : 2019-01-18 16:30
# @Author  : 一个从大山到原野的孩子
# @完成时间:
#项目根据已有的0-9的数据,识别手写数据。from numpy import *
import operator
from os import listdir
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from os import listdir"""
kNN: k Nearest NeighborsInput:      inX: vector to compare to existing dataset (1xN)dataSet: size m data set of known vectors (NxM)labels: data set labels (1xM vector)k: number of neighbors to use for comparison (should be an odd number)Output:     the most popular class label
"""
#下载文件后  根据保存文件的路径 更新相关路径
#inputfile='C:\\Users\\yuanye\\Desktop\\code\\testDigits\\0_13.txt'def file2matrix(filename):"""Function:   从文本文件中解析数据Args:       filename:文件名称字符串Returns:    returnMat:训练样本矩阵classLabelVector:类标签向量""" #打开文件fr = open(filename)#得到文件行数numberOFLines = len(fr.readlines())#创建返回的NumPy矩阵returnMat = zeros((numberOFLines, 3))#创建返回的向量列表classLabelVector = []fr = open(filename)index = 0for line in fr.readlines():#使用line.strip()截取掉多有的回车符line = line.strip()#使用tab字符将上一步得到的整行数据分割成一个元素列表listFromLine = line.split(',')#选取前三个元素,存储到特征矩阵中returnMat[index, :] = listFromLine[0:3]#将列表最后一列存储到向量classLabelVector中classLabelVector.append(int(listFromLine[-1]))index += 1#返回训练样本矩阵和类标签向量return returnMat, classLabelVectordef classify_knn(inX, dataSet, labels, k):"""Function:   创建数据集和标签Args:      inX:用于分类的输入向量 (1xN)dataSet:输入的训练样本集 (NxM)labels:标签向量 (1xM vector)k:用于比较的近邻数量 (should be an odd number)Returns:    sortedClassCount[0][0]:分类结果"""#dataSet.shape[0]:求dataSet矩阵的行数#dataSet.shape[1]:求dataSet矩阵的列数#dataSet.shape:元组形式输出矩阵行数、列数#数组何矩阵才有shape属性dataSetSize = dataSet.shape[0]#tile(A, B):将A重复B次,其中B可以是int类型也可以是元组类型 B=(3,2) 3行、原数据出现2次#tile 是numpy数组 功能是重复某个数组#向量inX与矩阵dataSet里面的每组数据做差diffMat = tile(inX, (dataSetSize, 1)) - dataSet#对求差后的矩阵求平方sqDiffMat = diffMat**2#sqDiffMat.sum(axis=0):对矩阵的每一列求和#sqDiffMat.sum(axis=1):对矩阵的每一行求和#sqDiffMat.sum():对整个矩阵求和sqDistances = sqDiffMat.sum(axis=1)#求平方根distances = sqDistances**0.5#print("distances",distances)#对上式结果进行排序  返回的是按升序排列后的索引值#知识延伸-Sort函数是list列表中的函数,而sorted可以对list或者iterator进行排序#sort 操作的是内存;sorted 操作的是视图#sorted有多个排序参数 cmp key reverse itemgetter#cmp key 结合lambda排序,itemgetter 可以多级排序 列值顺序以元祖形式给出sortedDistIndicies = distances.argsort()#print("sortedDistIndicies",sortedDistIndicies)#创建字典classCount = {}#给字典赋值for i in range(k):#字典的keyvoteIlabel = labels[sortedDistIndicies[i]]#classCount.get(voteIlabel,0):如果字典键的值中有voteIlabel,#则返回0(第二个参数的值)classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1#对classCount进行排序,sroted、items以及itermgetter 字典排序sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)#返回分类结果return sortedClassCount[0][0]def knn_scatter(inputfile):'''#简单作图方法fig = plt.figure()ax = fig.add_subplot(111)ax.scatter(x,y,x1,y1)plt.show()'''n = 1000 #number of points to createxcord1 = []; ycord1 = []xcord2 = []; ycord2 = []xcord3 = []; ycord3 = []markers =[]colors =[]fw = open(inputfile)for i in range(n):[r0,r1] = random.standard_normal(2)myClass = random.uniform(0,1)if (myClass <= 0.16):fFlyer = random.uniform(22000, 60000)tats = 3 + 1.6*r1markers.append(20)colors.append(2.1)classLabel = 1 #'didntLike'xcord1.append(fFlyer); ycord1.append(tats)elif ((myClass > 0.16) and (myClass <= 0.33)):fFlyer = 6000*r0 + 70000tats = 10 + 3*r1 + 2*r0markers.append(20)colors.append(1.1)classLabel = 1 #'didntLike'if (tats < 0): tats =0if (fFlyer < 0): fFlyer =0xcord1.append(fFlyer); ycord1.append(tats)elif ((myClass > 0.33) and (myClass <= 0.66)):fFlyer = 5000*r0 + 10000tats = 3 + 2.8*r1markers.append(30)colors.append(1.1)classLabel = 2 #'smallDoses'if (tats < 0): tats =0if (fFlyer < 0): fFlyer =0xcord2.append(fFlyer); ycord2.append(tats)else:fFlyer = 10000*r0 + 35000tats = 10 + 2.0*r1markers.append(50)colors.append(0.1)classLabel = 3 #'largeDoses'if (tats < 0): tats =0if (fFlyer < 0): fFlyer =0xcord3.append(fFlyer); ycord3.append(tats)    fw.close()fig = plt.figure()ax = fig.add_subplot(111)#ax.scatter(xcord,ycord, c=colors, s=markers)type1 = ax.scatter(xcord1, ycord1, s=20, c='red')type2 = ax.scatter(xcord2, ycord2, s=30, c='green')type3 = ax.scatter(xcord3, ycord3, s=50, c='blue')ax.legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)ax.axis([-5000,100000,-2,25])plt.xlabel('Frequent Flyier Miles Earned Per Year')plt.ylabel('Percentage of Time Spent Playing Video Games')plt.show()def autoNorm(dataSet):"""Function:   归一化特征值Args:       dataSet:训练验本矩阵Returns:   normDataSet:归一化矩阵ranges:每一列的差值minVals:每一列的最小值""" #求取列的最小值minVals = dataSet.min(0)#求取列的最大值maxVals = dataSet.max(0)#最大值与最小值做差ranges = maxVals - minVals#创建输出矩阵normDataSetnormDataSet = zeros(shape(dataSet))#m设定为矩阵dataSet的行数m = dataSet.shape[0]#对矩阵dataSet每个元素求差normDataSet = dataSet - tile(minVals, (m, 1))#对矩阵dataSet每个元素归一化normDataSet = normDataSet/tile(ranges, (m, 1))#返回归一化矩阵、差值向量和最小值向量return normDataSet, ranges, minValsdef datingClassTest():"""Function:   分类器测试代码Args:       无Returns:    classifierResult:分类器分类结果datingLabels[i]:真实结果errorCount:分类误差""" #测试集比例设定:10%hoRatio = 0.1#从文本文件中解析数据datingDataMat, datingLabels = file2matrix(inputfile)#归一化特征值normMat, ranges, minVals = autoNorm(datingDataMat)#计算normMat矩阵行数并赋值给mm = normMat.shape[0]#初始化测试向量个数numTestVecs = int(m*hoRatio)#初始化错误计数errorCount = 0.0#对测试集分类,返回分类结果并打印for i in range(numTestVecs):#传参给分类器进行分类,每个for循环改变的参数只有第一项的测试数据而已classifierResult = classify_knn(normMat[i,:], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)#打印当前测试数据的分类结果个真实结果print("the classfier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))#如果分类结果不等于真是结果,错误计数加一if (classifierResult != datingLabels[i]): errorCount += 1.0#输出测试错误率print("the total error rate is: %f" % (errorCount/float(numTestVecs)))#输出测试错误数print(errorCount)def classifyPerson():"""Function:   约会网站测试函数Args:       percentTats:玩视频游戏消耗时间百分比ffMiles:每年获得的飞行常客里程数iceCream:每周消费的冰淇淋公升数Returns:    resultList:可交往程度"""#建立输出列表resultList = ['not at all', 'in small doses', 'in large doses']#读取键盘输入的数值percentTats = float(input("percentage of time spent playing video games?"))ffMiles = float(input("frequent flier miles earned per year?"))iceCream = float(input("liters of ice cream consumed per week?"))#从文本文件中解析数据datingDataMat, datingLabels = file2matrix(inputfile)#归一化特征值normMat, ranges, minVals = autoNorm(datingDataMat)#将先前读取的键盘输入填入数组inArr = array([ffMiles, percentTats, iceCream])#分类:这里也对输入数据进行了归一化classifierResult = classify_knn((inArr - minVals) / ranges, normMat, datingLabels, 3)#打印分类信息print("You wil probably like this person: ", resultList[classifierResult - 1])def img2vector(filename):"""Function:   32*32图像转换为1*1024向量Args:       filename:文件名称字符串Returns:    returnVect:转换之后的1*1024向量""" #初始化要返回的1*1024向量print("filename",filename)returnVect = zeros((1, 1024))#打开文件fr = open(filename)#读取文件信息for i in range(32):#循环读取文件的前32行lineStr = fr.readline()for j in range(32):#将每行的头32个字符存储到要返回的向量中returnVect[0, 32*i+j] = int(lineStr[j])#返回要输出的1*1024向量return returnVectdef handwritingClassTest():"""Function:   手写数字测试程序Args:       无Returns:    returnVect:转换之后的1*1024向量""" #初始化手写数字标签列表hwLabels = []#获取训练目录信息trainingFileList = listdir('C:\\Users\\yuanye\\Desktop\\code\\trainingDigits')#获取训练文件数目m = len(trainingFileList)print(m)#初始化训练矩阵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('C:\\Users\\yuanye\\Desktop\\code\\trainingDigits\\%s' % fileNameStr)#获取测试目录信息testFileList = listdir('C:\\Users\\yuanye\\Desktop\\code\\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('C:\\Users\\yuanye\\Desktop\\code\\testDigits\\%s' % fileNameStr)#参数传入分类器进行分类classifierResult = classify_knn(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)))if __name__ == '__main__':#print("datingDataMat",datingDataMat)#knn_scatter(inputfile)#datingClassTest()#classifyPerson()#testVector = img2vector(inputfile)#print("testVector",len(testVector))handwritingClassTest()

Python3:《机器学习笔记与实战》之Knn算法(2)识别手写数字相关推荐

  1. 机器学习实战2.3. k-近邻算法例子-识别手写数字

    机器学习实战2.3. k-近邻算法例子-识别手写数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多机器学习干货 csdn:https://blog.csdn.net/ ...

  2. python与人工智能:KNN近邻法识别手写数字

    机器学习分类? 1 特征(feature) 数据是区分事物和事物的关键. 举例:不同类型的书,我们用书的内容来对它进行分类 2 标签(label) 数据的标签,显示的分类结果. 举例:书属于的类别,例 ...

  3. Tensorflow实战之实现 Softmax Regression识别手写数字(学习笔记)

    Tensorflow概要 Tensorflow是google的分布式机器学习系统,其既是一个实现机器学习算法的接口,同时也是执行机器学习算法的框架.它前段支持python.C++,Go,Java等多种 ...

  4. OpenCV-Python实战(番外篇)——利用 KNN 算法识别手写数字

    OpenCV-Python实战(番外篇)--利用 KNN 算法识别手写数字 前言 手写数字数据集 MNIST 介绍 基准模型--利用 KNN 算法识别手写数字 改进模型1--参数 K 对识别手写数字精 ...

  5. 机器学习实战之k-近邻算法识别手写数字(含拍照检验步骤详解)

    哈哈,这是我写的第一篇博客,就此拉开了我的程序员生涯的序幕.希望有缘人看见之后,能够解决你所遇见的问题.废话不多说,开始办正事. 本例中使用K-近邻算法识别手写数字,参考书目:Peter Harrin ...

  6. svm手写数字识别_KNN 算法实战篇如何识别手写数字

    上篇文章介绍了KNN 算法的原理,今天来介绍如何使用KNN 算法识别手写数字? 1,手写数字数据集 手写数字数据集是一个用于图像处理的数据集,这些数据描绘了 [0, 9] 的数字,我们可以用KNN 算 ...

  7. OpenCV-Python实战(番外篇)——利用 SVM 算法识别手写数字

    OpenCV-Python实战(番外篇)--利用 SVM 算法识别手写数字 前言 使用 SVM 进行手写数字识别 参数 C 和 γ 对识别手写数字精确度的影响 完整代码 相关链接 前言 支持向量机 ( ...

  8. opencv(python)使用knn最近邻算法识别手写数字

    knn最近邻算法是一种分类以及回归算法,算法原理是一个样本与样本集中k个样本最相似,如果这k个样本的大多数也属于同一个类别,则该样本也属于这一类.关于knn算法的详细原理读者可以在网上找一些资料了解下 ...

  9. 机器学习算法 08 —— 支持向量机SVM算法(核函数、手写数字识别案例)

    文章目录 系列文章 支持向量机SVM算法 1 SVM算法简介 1.1 引入 1.2 算法定义 2 SVM算法原理 2.1 线性可分支持向量机 2.2 SVM计算过程与算法步骤(有点难,我也没理解透,建 ...

最新文章

  1. TensorFlow 实现分类操作的函数学习
  2. 【MM配置】Global Data 全局数据相关配置
  3. qt最大化和还原实现_研究进展 | 水生所关于细菌异化型硝酸盐还原成铵与反硝化脱氮两种途径抉择的分子调控机制研究取得进展...
  4. ASP.NET(c#)如何判断浏览器是否支持cookies
  5. 093:QuerySet API详解-QuerySet转换为SQL的条件
  6. HDU 5680 zxa and set 水题
  7. 树莓派开启samba服务
  8. ffdshow 源代码分析 7: libavcodec视频解码器类(TvideoCodecLibavcodec)
  9. 【细节实现题】LeetCode 57. Insert Interval
  10. 教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
  11. 软件生命周期、面向对象基本概要
  12. [RK3288][Android6.0] 调试笔记 --- RT5640播放时的Codec寄存器列表
  13. 黑暗传说作弊工具的IOS安卓
  14. SAP成都研究院非典型程序猿,菜园子小哥:当我用UI5诊断工具时我用些什么
  15. Python 日志logging模块初探及多线程踩坑(2)
  16. 文本相关_SAP刘梦_新浪博客
  17. 【Matlab】删除cell中所有的空白cell.
  18. 亚马逊IP关联?卖家
  19. 卷帘相机和全局相机的区别(Rolling Shutter Global Shutter)
  20. windows10局域网设置固定IP地址

热门文章

  1. 使用 Docker 搭建 Hadoop 分布式环境
  2. Hadoop集群搭建(超级超级详细)
  3. 基于webSocket的聊天室
  4. 《Closure The Definitive Guide 》 Closure Libary 读书笔记
  5. ABAP ALV例程用法
  6. Jquery easyui tree的使用
  7. 吃鸡手游服务器未响应,PUBG Mobile Lite
  8. keyshot两种材质叠加_KeyShot两种照明方式
  9. IDEA设置 JDK1.8API中文提示
  10. mac安装旺旺启动台找不到_第一次用 Mac?推荐你先了解这些…