KNN实现手写数字识别Python

来源:互联网 发布:单片机温度控制器设计 编辑:程序博客网 时间:2024/05/02 06:04

本文章总结了KNN算法字手写数字识别的应用,比较系统的对传统KNN和各种改进的KNN算法进行实现,由于完整的代码量较大(部分代码参考了机器学习实战),不适合全部贴出,但是博主乐于分享,有需要的话可以直接联系我,我会很乐意共享的,一希望大家能帮我校准文章的错误啦~~~


首先用1500张手写数据进行训练,然后利用500张数字做测试,数据集大家可以搜手写数字识别数据集,网上很多,我过几天也会贴到我的资源库里面,欢迎打家下载,可以用notepad++查看每个数字。

KNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。算法步骤如下:

输入:训练数据集T={(x1,y1),(x2,y2),…,(xn,yn)}

输出:实例x所属的类y

(1)根据给定距离度量,在训练集T中找出与x最近邻的k个点,涵盖这k个点的x的领域记作Nk(x)

(2)在Nk(x)中根据分类决策规则(多数表决)决定x的类别y


4.12 核心代码

首先构造一个分类起,该分类器接收训练数据集合待测实例,返回待测实例的分类。


然后从分别从数据文本中获取训练数据集和测试数据集,并调用classifyEU方法,输出结果


结果如下:



二、改进距离

        欧氏距离虽然很有用,但也有明显的缺点。它将样品的不同属性(即各指标或各变量)之间的差别等同看待,这一点有时不能满足实际要求。例如,在教育研究中,经常遇到对人的分析和判别,个体的不同属性对于区分个体有着不同的重要性。因此,有时需要采用不同的距离函数。这里采用马氏距离。

结果如下:


       出乎意料,使用马氏距离后,分类器的效果奇差,错误率达到56%,这显然是不能令人满意的。可能原因是由于马氏距离是把各个特征维度的相关性考虑进去,但是手写数字系统各个维度并没有很大的相关性,并且由于各个维度的取值都只是0和1两种,因此效果非常差,这也说明各个距离都有自己的适用场合,我们需要根据数据的实际意义和特征,选取恰当的距离度量,才能去得良好地效果。


三、SAHIBSINGH A. DUDANI 等在The Distance-Weighted k-Nearest-Neighbor Rule 中提出一种改进权重的KNN方        法,这里用Python实现看看效果是不是真有那么好,哈哈。

      论文大家可以自己下载:核心思想是距离测试点更近的点应该赋予更大的权值,二距离远的点应该赋予更小的权值。权值公式为


核心代码:


运行结果:


可以看到WKNN算法的错误个数是10,错误率约1.06%,准确率约98.94%,所用时间约49.408秒,准确率相对KNN有所提高,SAHIBSINGH A. DUDANI诚不欺我也~~~


另外P. Viswanath and T. Hitendra Sarma等在An Improvement to k-Nearest Neighbor Classifier中提出另一种改进KNN方法,经博主实验证明改算法在手写数字识别数据集的准确率可以达到99%+,几乎可以赶上神经网络的正确率了,看来经过捣鼓捣鼓得KNN果然是良心算法呀,简单实用,哈哈。但是该改进算法运算量相对比较大,因为需要对每一个类求K个近邻。


四、kd-Tree

       实现k近邻法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索,这点在特征空间的维数大以及训练数据容量大时尤其重要。为了提高k近邻搜索的效率,考虑使用特殊的结构存储训练数据,以减少计算距离的次数。通过构造kd_Tree来实现。

        Kd-Tree是一个二叉树,每个节点表示的是一个空间范围。下表表示的是Kd-树中每个节点中主要包含的数据结构。Range域表示的是节点包含的空间范围。Node-data域就是数据集中的某一个n维数据点。分割超面是通过数据点Node-Data并垂直于轴split的平面,分割超面将整个空间分割成两个子空间。令split域的值为i,如果空间Range中某个数据点的第i维数据小于Node-Data[i],那么,它就属于该节点空间的左子空间,否则就属于右子空间。Left,Right域分别表示由左子空间和右子空间空的数据点构成的Kd-Tree。

核心代码:

首先创建一个树节点




运行结果:



       看到这个结果博主心里是蓝瘦香菇的,这哪里改进了运行效率嘛,运行时间分明比不用KD-Tree还长很多,不过博主还是耐心的分析了原因,果然还是有所发现,在运行效率方面,根据经验,kd-Tree只在:特征维数远小于样本数的情况下才是比较平衡的,而该训练数据集特征维数为1024和训练样本数接近,并且每一个维度都只有0和1两个值,因此构造出来的是一个极度不平衡的树,当树完全不平衡的时候其效率和逐个遍历没有什么区别,因此并没有使运行时间效率提升,反而因为需要构造kd-Tree、比较等操作使得运行效率相对较低,由此得到的教训是并不是一个好的算法思路就能拿来用呀,关键还得看场景!场景!场景!





0 0
原创粉丝点击