山东大学数据结构课程设计 —— KNN分类器应用于手写数字识别、数据结构KD树的实现以及其K近邻搜索(1)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

在上面的分析中:

K的选取一般来源于经验,一般选取一个较小的大于1的奇数,一般在 ( 1 , n ) (1,\sqrt n) (1,n ​)。

  1. n较小时,n取 ( 1 , 10 ) (1,10) (1,10)中的奇数;
  1. n较大时,n取 ( 1 , n / 2 ) (1,\sqrt n/2) (1,n ​/2)中的奇数;

并且考虑到,k的值对预测结果的敏感程度,所以在k较小的时候,步数尽可能小;在 k取值较大的时候,步数可以适量增大。

假定样本容量为 n n n, n n n的量级大概在 1 0 6 10^6 106自由,

所以 k k k不超过 n / 2 \sqrt n/2 n ​/2,也就是500。

所以,k的步长可以这样设计,

从3开始,为了保证k的取值是偶数,

  1. 1~10内,步长为2;

  2. 10~30内,步长为4;

  3. 30~60,步长为6;

  4. 60~100,步长为8;

  5. 100~500, 步长为40;

如此,既减少了模型训练、测试样本的时间,又在一定程度上表现了随着k的变化,对分类正确率的影响

图像特征的数字化


本次实现的KNN分类器的最终目标是实现一个建议的手写字体识别器。

因此,对图像数字特征的提取工作就变得尤为关键。

下面介绍几个常见的 图像特征提取算法

暴力算法

将图像的每一个像素点都作为特征向量的一个维度,很明显。

这样做的缺点是非常明显的,甚至可以说毫无优点。

  • 特征维度提取不精确

有一些并属于图像的像素也被作为特征维度,相当于成了噪声点 —— 也 就是说并没有很好的体现图像的拓扑学关系。

  • 维度太高

向量的维度太高,会带来一系列问题。内存占用太多,计算量迅速增大,并且对于高维向量的检索KD树表现的很差(几乎接近暴力的线性扫描的复杂度)。

以下内容均来自这篇文章

SIFT

SIFT:Scale-Invariant Feature Taransform,尺度不变特征变换

  • 尺度空间的极值检测:搜索所有尺度空间上的图像,通过高斯微分函数来识别潜在的对尺度和旋转鲁棒性较强的点。

  • 特征点定位:在每个候选位置上,通过一个拟合精细模型(尺度空间DoG函数进行曲线拟合)来确定位置尺度,关键点的选取依据他们的稳定程度。

特征方向赋值:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向,后续的所有操作都是对于关键点的方向、尺度和位置进行变换,从而提供这些特征的不变性。

  • 特征点描述:在每个特征点周围的领域内,在选定的尺度上测量图像的局部梯度,计算块内梯度直方图,生成具有独特性的向量。

HOG

HOG:Histogram of Oriented Gradient,方向梯度直方图

  • 颜色空间归一化:为了减少光照因素的影响, 首先需要将整个图像归一化。因为颜色信息作用不大,通常先转化为灰度图。

  • 梯度计算:计算图像横坐标和纵坐标方向的梯度,并据此计算每个像素位置的梯度+ 方向值;求导操作不仅能捕获轮廓,还能进一步弱化光照的影响。

  • 梯度方向直方图:将图像分成若干个cell,对cell内每个像素用梯度方向在直方图中进行加权投影(映射到固定的角度范围),就可以得到这个cell的梯度直方图。

将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。

组成特征:将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor。

LBP

LBP:Local Binary Pattern,局部二值模式

原始的LBP算子定义在像素3_3的邻域内,以邻域中心像素为阈值,相邻的8个像素的灰度值与邻域中心的像素值进行比较,若周围像素大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3_3邻域内的8个点经过比较可产生8位二进制数,将这8位二进制数依次排列形成一个二进制数字,这个二进制数字就是中心像素的LBP值,LBP值共有28种可能,因此LBP值有256种。中心像素的LBP值反映了该像素周围区域的纹理信息。

值得一提的是,即使暴力法有诸多不好,但是很多机器学习的教材上仍然将它作为特征提取的一种方法,原因是图像的特征解析已经和机器学习的内容关系不大了,

所以对初学者使用暴力法即可。

而本次任务是实现KNN算法,并且用KD树进行优化。

数据结构设计

======================================================================

这部分内容,放在了这篇博客详细介绍了。

传送门

应用程序设计

======================================================================

功能模块


下面介绍在此次课程设计中根据功能解耦拆分出来的功能模块。

如下。

画图模块

画图模块,使用JavaScript 和 canvas 标签完成。

完成的功能很简单,按住鼠标左键的同时移动鼠标,然后开始作图。

下方有两个按钮,清空按钮和识别按钮。

在这里插入图片描述

解析图形模块

这部分已经在上文的

图像特征的数字化

详细介绍过了,这里略去不谈。

样本数据加载模块

因为本次识别使用到了OpenCV官方给的数据集,而OpenCV官给的手写数字的数据集是用IDX文件格式的存储的。

而这样的文件格式虽然最高效的存储了图片信息,但是对于java来解析它,却绝非易事,所以样本数据加载模块的功能就是解析idx文件,

即可以生成可视化的图片,也生成以矩阵或者向量形式呈现出来的图片。

在处理IDX文件之前,必须对它的存储有一定了解。

有关IDX文件格式的信息: IDX文件格式是各种数值类型的向量和多维矩阵的简单格式. 基本格式是:

magic number size in dimension 0 size in dimension 1 size in

dimension 2 … size in dimension N data

幻数是一个整数(MSB优先).前2个字节始终为0.

第三个字节编码数据的类型:

0x08: unsigned byte 0x09: signed byte 0x0B: short (2 bytes) 0x0C:

int (4 bytes) 0x0D: float (4 bytes) 0x0E: double (8 bytes)

第4个字节编码向量/矩阵的维数:1表示向量,2表示矩阵….

每个维度的大小为4字节整数(MSB优先,高端,与大多数非英特尔处理器一样).

数据存储在C数组中,即最后一维中的索引变化最快.

在这里插入图片描述

idx文件解析完之后加载之后,可以看到官方给的手写字体的图片。

(图片大小为28*28)

在这里插入图片描述

浮点算法:

G r a y = R ∗ 0.3 + G ∗ 0.59 + B ∗ 0.11 Gray=R*0.3+G*0.59+B*0.11 Gray=R∗0.3+G∗0.59+B∗0.11

依次提取出每个像素的点的RGB值之后,根据灰度公式

G r a y = R ∗ 0.3 + G ∗ 0.59 + B ∗ 0.11 Gray=R*0.3+G*0.59+B*0.11 Gray=R∗0.3+G∗0.59+B∗0.11

提取出图片的矩阵呈现形式。由于矩阵太大,无法全部显示出来。

这里将其缩放乘8*8的图片并以灰度矩阵的形式展示出来。

分类器模块

  • 训练模型的构建

将样本数据集标准化,然后

  • 超参数k的选取

这部分内容在上面以及详细介绍过,此处略去。

测试模块

控制变量法研究不同因素的对分类器效率的影响。

这个模块会在下面详细介绍,这里就略去不谈了。

数据结构可视化模块

为了动态显示KD树的构建、插入节点等操作,以及实现KNN算法的可视化。

使用开源的 echarts 组件,实现树结构的可视化。

上面有三个按钮,分别是KD树的动态插入、重建KD树(利用样本集构建一个KD树)、以及显示二维向量的平面化展示。

同时,点击平面化的点,可以显示它周围的3个邻居,同时在树上实时显示。

在这里插入图片描述

测试和运行

=====================================================================

在测试KNN算法实现的分类器的时候,我们有这几个参数或因素是非常关心的,它们对KNN分类器的效率和准确率:

  1. 邻居个数的k的选择

  2. 向量维度K的不同

  3. 距离计算公式的选择

  4. 决策函数的选择

  5. 采用的训练模型:暴力扫描、KD树搜索

自然,使用控制变量法去研究不同因素的对KNN分类器的影响是非常有必要的。

邻居个数的k的选择


在本次实验中,样本容量为60000,

采取10折交叉验证法,对不同取值的超参数 k k k,评估了算法模型的准确率。

见下面两张图:随着k的增大,分类器识别的错误率基本上也在增大。

在这里插入图片描述

值得关注的是,在k = 3 ,5, 7等值的附近时,

出现了全局最优解,也就是在 k = 7 k = 7 k=7的时候,分类器的错误率达到了最低,也就是说识别率达到了最高。

在这里插入图片描述

通过实践证明, k k k一般情况下确实不应该选择一个比较大的数,一般情况下取得比较小。当然这也只是经验之谈。

具体的选择,还要根据实际问题、样本容量等具体因素通过一些验证法得出最优选择。

总结

==================================================================

KNN算法的优缺点


  • 优点
  1. 算法本身简单、易于理解和实现

  2. 精度较高、对异常值不敏感

  3. 适用于大样本自动分类

  4. 需要参数估计很少,只有一个邻居个数 k k k

  5. 惰性学习,学习阶段仅仅是保存数据而已

  • 缺点

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

分类

  1. 需要参数估计很少,只有一个邻居个数 k k k

  2. 惰性学习,学习阶段仅仅是保存数据而已

  • 缺点

[外链图片转存中…(img-icPrze1e-1715458296487)]
[外链图片转存中…(img-O9gzu3Qw-1715458296487)]
[外链图片转存中…(img-1f5AQ9Ut-1715458296487)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

  • 24
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值