文章目录
- 机器学习算法学习01:利用Numpy编写KNN算法解决手写体数字识别问题
- 前言
- 1.算法介绍
- 2.数据集介绍
- 3.先决条件:安装numpy,sklearn库
- 4.算法代码编写
- 5.实验结果分析
- 5.1 保持其他变量不变,修改计算距离方式
- 1.计算距离采用mse(均方绝对误差):
- 2 计算距离采用RMSE(均方根误差)方式:
- 5.2 保持其他变量不变,修改k的个数
- 5.3 保持其他变量不变,修改测试数据与训练样本的比值
- 补充实验
- 结语
前言
在深度学习未彻底被大众接受前,人们对人工智能的研究是企图研究出一系列巧妙的算法解决相关计算机视觉问题,这里面涌现了无数令人叹为观止的算法(随机森林,遗传算法,SVM,马尔科夫链,KNN等)即使在深度学习逐渐占据解决计算机视觉人工智能问题的算法的今天,不可否认,依旧有许多深度学习算法吸收了这些传统算法的思想,从而来进行改进,所以学习这些传统算法也是非常有必要的??????。本次我们介绍的是如何利用numpy库来构造KNN算法解决手写体数字识别问题。
1.算法介绍
KNN算法全称(K-NearestNeighbor)直译为K个最近的邻居,是一种聚类算法。该算法认为我们在判断一个物体的类别可以根据与他非常相似的K个物体的类别(这K手写数字个物体的类别是已知的)来决定。
举个例子,假设我们需要鉴别某个水果的类别,我们通过比对发现他和我们拥有的水果中7个物品非常相似,我们发现这七个物品其中6个是西瓜,一个是菠萝,所以我们自然的认为这个物品是西瓜。这就是一个7NN算法。

直观一点,我们可以观察上图。该图之中存在三个类别ω1,ω2 ω3。我们使用5NN寻找五个与X相邻最近的点发现其中四个属于ω1那么我们就可以推断出X属于ω1类别。
看了上面两个例子,相信你应该对KNN算法有了基础的认识了吧,那么我们这里可以先总结出他的流程:
输入:数据x 已知类别的样本z 输出:x的类别y
开始
- 计算数据x与z中每个样本的距离d
- 利用距离d获取与x距离前K小的索引index
- 利用index从样本z中选取出k个样本
- 统计这k个样本的类别,类别数统计最多的作为x的类别
结束
2.数据集介绍
这里我们使用的是sklearn库提供的手写体数据集,该数据集包括了1797张手写的0-10的图片
通过以上的代码我们可以查看图片的内容,我们看出来这些其实就是一系列0-10的图片(如下两张就是0和2)(由于设置的是随机取出,所以可以多运行几次,每次运行的结果都不一样)


3.先决条件:安装numpy,sklearn库
python由于他的方便简单,前人开发了无数的易于使用的库,但是这些并不会随着你的安装而自动安装(sklearn库好像会自动安装),所以我们需要自己输入命令来安装,不过也是非常简单的这里如果遇到不知道使用什么命令可以查看这个网站:
Search results · PyPI
利用这个网站查询结果如下,我们复制命令 pip install numpy即可

然后我们如果是在windows系统上直接,同时按下win键和R键,在弹出的窗口中输入cmd并执行,最后在弹出的命令行界面中输手写数字入查询到的命令:
等待下载完成即可,如果遇到下载速度非常慢的话可以使用这个博客的方法(解决 ERROR: Could not find a version that satisfies the requirement
xxx 的问题_JMU-HZH的博客-CSDN博客)
安装sklearn库也同理。
4.算法代码编写
在此次手动实现KNN算法中,我一共写了两个py文件,KNN.py和run.py。其中KNN.py实现了kNN算法,而run.py则为程序启动脚本,让我们来一一介绍吧???♂????♂????♂?:
KNN.py
run.py:
5.实验结果分析
在本次实验中存在三个可供我们调整的变量,分别是测试数据与训练数据的比值,计算距离的方法,选取的近邻个数K。接下来我们使用控制变量法来修改他们观察正确率的变化。
先给定我们的baseline,当测试数据与训练数据数量比为 1 :4,计算距离采用mae平均绝对误差时准确率为0.986

5.1 保持其他变量不变,修改计算距离方式
1.计算距离采用mse(均方绝对误差):

多次实验正确率为0.994到0.97,取二者平均值计算约为0.986
2 计算距离采用RMSE(均方根误差)方式:

多次实验正确率稳定在0.978左右
5.2 保持其他变量不变,修改k的个数
k = 3, accuracy = 0.983
k=4, accuracy = 0.986
k = 5 accuracy = 0.986
k=6, accuracy = 0.972
k=7,accuracy = 0.985
k=8,accuracy = 0.978
k=9,accuracy=0.980
k=10, accuracy=0.971
5.3 保持其他变量不变,修改测试数据与训练样本的比值
比值为 3:7 , accuracy=0.976
比值为4:6,accuracy = 0.976
比值为1:1, accuracy = 0.971
比值为6:4,accuracy= 0.967
比值为7:3,accuracy=0.965
比值为8:2,accuracy=0.949
比值为9:1,accuracy=0.869
通过以上三个控制变量实验,我们可以发现
- 修改计算数据与数据之间距离方式对提升正确率并无太大作用,其中使用mae和mse效果最好,RMSE效果较差
- 可以看出来当K的值越发上升时正确率开始逐渐下降,可能是由于当决定数据类别的“近邻”太多时噪声过多影响了精度
- 而调整测试数据与训练样本的比值则会影响正确率,可以看到当测试数据越来越多训练样本越来越少模型正确率越来越低吗,我们可以看出使用KNN我们的训练样本必须尽可能地多,以保证我们的准确率。
补充实验
另一个是博主学习的教材提供的约会网站数据集(Manning | Machine Learning in Action),该网站数据统计每个用户的三种数据:
- 每年获得的飞行常客里程数
- 玩视频游戏(video games)所耗时间百分比
- 每周消耗的冰淇淋公升数
并将所有人分为三类:
- 不喜欢的人
- 魅力一般的人
- 极具魅力的人
我们的问题就变成了根据上面三个统计数据,将用户进行分类。
数据被放在一个TXT的文件夹中,其中每行共四个数据,前三个为前面提到的三个统计数据,后一个为用户的分类结果。我们按照这样的格式制作读取文件函数:
获得这些统计数据之后,我们可以使用绘图库进行绘制图片来可视化数据:

但有时候我们需要注意,就是这些输入特征的数量级到底是不是一致的(如果是手写体识别我们并不需要注意这个问题),比如说一个人的飞行里程数可能有达到万里程级别,但是一个人吃冰淇淋可能一周只能吃几升,这会导致比起其他条件,飞行里程数实际上更影响我们的分类结果,权重更大。所以我们还需要对所有输入特征进行归一化,将所有输入特征的数值降低到[0,1]之间,消除数量级的差别,从而使所有输入特征对分类结果的影响保持一致。
我们的数据在归一化完之后,接下来就可以使用KNN算法来对它进行分类了:
结语
在本次实验中,我完成了独立编写kNN算法的任务,并通过控制变量法完成了对于kNN中各个变量影响性能的研究。同时我也认识到传统机器学习算法的设计巧妙,即使在深度学习一统江湖的今天,它对我们这些人工智能的后来者依旧具有非常好的启示意义,值得我们去认真学习。