机器学习 常用算法(一. K-近邻算法)

本文深入介绍了K-近邻学习算法(KNN),包括其定义、工作原理、优缺点和适用数据类型。通过案例分析了欧式距离在KNN中的应用,探讨了不同距离度量对结果的影响。此外,文章提到了KNN在大数据集中的优化方法——KD树,以及如何使用KD树进行最近邻域的搜索。最后,简述了Python的scikit-learn库在KNN算法中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

K-近邻学习算法(k-Nearest Neighbor,简称KNN)

定义:如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本的大多数属于某一个类别(即分类任务中的投票法),则这样本也属于这个类别。
通俗解释:通过邻居来判断自己的类别是什么。例如不知道自己的位置的时候,看距离自己最近的大多数人来判定。因而,可知这个算法属于分类算法。


西瓜书定义:给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测(K近邻学习是一种常用的监督学习方法,也是“懒惰学习”的著名代表)。


工作原理:

  1. 存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每个数据与所属分类的对应关系。
  2. 输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。
  3. 一般来说,只选择样本数据集中前N个最相似的数据(k一般不大于20),最后,选择k个中出现次数最多的分类,作为新数据的分类。

读完本篇相信大家会对KNN算法有如下体会:

  • 优点:精度高,对异常值不敏感,无数据输入假定
  • 缺点:计算复杂度高,空间复杂度高
  • 适用数据范围:数值型和标称型

下面我们来深入了解相关概念和原理


欧式距离(Euclidean distance):两个样本的距离可通过以下公式计算,这种距离叫欧式距离。下边分别是二维和三维空间中欧氏距离的定义:

在这里插入图片描述
在这里插入图片描述
n维空间中点A(x11,x12,…x1n)与B(x21,x22,…x2n)间的距离(欧氏距离):

在这里插入图片描述


在学习中找了一个形象的案例

在这里插入图片描述
判断最后一个电影的类型,用三维空间中的欧氏距离,依次进行计算:

在这里插入图片描述
k=5代表选取了与《唐人街探案》欧式距离最近的 5(k的取值设为5) 个样本点,然后根据这些它们对应的电影类型,大多属于哪一类,那么唐人街就属于哪一类。


当然,采用不同的距离计算方式(非欧氏距离),则找出的近邻可能会有显著差别,从而也会导致分类结果的显著不同(即对唐人街探案属于类别的最后判定不同),常见的距离度量还有如下几种

Lp距离:

在这里插入图片描述
曼哈顿距离:

在这里插入图片描述
L∞距离:

在这里插入图片描述
还有余弦距离、汉明距离、马氏距离等方式,大家感兴趣可以查阅资料进行了解


对于k近邻分类器中的k,比如上述的5,如果设定为其他值(即通过选择的距离算法计算后,找出6个,7个…与它最近的距离来找样本点),那么最终的结果也会不同,可结合上述案例进行分析,k值的选择具体会带来什么影响呢(引用李航《统计学习方法》中的描述)(注:在第三章大约第50页的位置):

  1. 如果选择较小的K值,“学习”的近似误差(approximation error)会减小,但“学习”的估计误差(estimation error) 会增大,K值的减小就意味着整体模型变得复杂,容易收到异常点的影响,而发生过拟合
  2. 如果选择较大的K值,减少学习的估计误差,但缺点是学习的近似误差会增大。K值的增大就意味着整体的模型变得简单,受到样本均衡的问题易发生欠拟合(近似误差:对现有的训练集的训练误差,过小容易发生过拟合。估计误差:可理解为对测试集的误差,一般越小越好)

遇到较为复杂问题的时候,计算往往比上述案例更加复杂,这就把人工智能中计算力摆在更突出的位置【人工智能的三大要素:数据,算法,计算力】:

下边进一步来对KNN进行学习:

1. scikit-learn

a. 什么是scikit-learn

scikit-learn中文社区的描述:

  1. 简单有效的工具进行预测数据分析
  2. 每个人都可以访问,并且可以在各种情况下重用
  3. 基于NumPy,SciPy和matplotlib构建
  4. 开源,可商业使用-BSD许可证
  5. 总结:scikit-learn 是基于 Python的机器学习工具,文档完善且规范,容易上手,有丰富的API

下边展示了scikit-learn包含的主要六大功能,图来源于scikit-learn中文社区

在这里插入图片描述
b. scikit-learn的安装:
pip3 install scikit-learn==0.19.1(安装需要Numpy,Scipy等库),可以用import sklearn来看是否安装成功。

我使用并推荐Anaconda进行安装,对此详细描述请点击这里参考博文,不再演示。对于使用pycharm的朋友,Anaconda的配置请点击这里参考博文,我的配置和运行如下:
在这里插入图片描述

2. K-近邻算法API初步使用

对于机器学习流程如下:

获取数据集 数据的基本处理 特征工程 机器学习 模型评估

相关步骤和简单案例如下:

在这里插入图片描述
3. KD树及其构造

数据集很大时,计算数据集每个点到预测点的距离,然后进行投票,成本非常高。针对N个样本,D个特征的数据集,其算法复杂度为O(DN2)

kd树:为了避免每次都重新算一遍距离,算法会把距离信息保存在一棵树里,这样在计算之前从树里查询距离信息。
基本原理:如果A和B距离很远,B和C就很近,那么A和C的距离也很远,有了这个信息,就可以在合适的时候跳过距离远的点,优化后的算法复杂度可以降低到O(DNlog(N))
在这里插入图片描述在这里插入图片描述
kd树是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一系列的k维超矩形区域。kd树的每一个结点对应于一个k维超矩形区域,利用kd数可以省去对大部分数据点的搜索,从而减少搜索的计算量。可以类别“二分查找”,对于一些数据的查找,一些簇状的数据子集没必要归属于查找的范畴。

案例分析:

下边是我看到视频中的一个总结很好,分享一下:

在这里插入图片描述
下边是李航《统计学习方法》中的一个实例,原问题是这样的:给定一个二维空间数据集:T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构造一个平衡kd树

在进行切分的过程,我作了分解总结,按顺序截图如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在以上的分割中,首先选定(7,2)作为根节点进行切割,原因和分析过程如下:

对上述的x坐标进行排排序:2,4,5,7,8,9 <1>
对上述的y坐标进行排排序:1,2,3,4,6,7 <2>

通过观察很明显<1>组中数据的方差稍微大一些,即更分散一些,所以选取x坐标找点,从中间的位置最先切,5或7都行,这里选取的是7,因此首先选定(7,2)。然后根据根节点划分(第二次),左面的点(2,3),(4,7),(5,4),右面的点(8,1),(9,6),对左面的点的y坐标进行排序3,4,7。右边的点的y坐标排序1,6。因此左边找(5,4),右边找(8,1)或(9,6)(可选这个)。继续划分(第三次),(2,3),(4,7)和(8,1),这次换x轴,排序,2,4和1,由于点少,不需要分其实就可做切割,因为选哪个点最后切割方式都唯一确定下来了,演示图如下:
在这里插入图片描述
4. 最近邻域的搜索

我们仍结合李航书(第55页左右)上的案例进行分析。假设标记为星星的点是test point,绿色的点是找到的近似点,在回溯过程中,需要用到一个栈或队列,存储需要回溯的点。在判断其他子节点空间中是否有可能有距离查询点更近的数据点,做法是以查询点为圆心,以当前的最近距离为半径画圆,这个圆成为候选超球(candidate hypersphere)。如果圆与回溯点的轴相交,则需要将轴另一边的节点都放到回溯队列里面来
在这里插入图片描述
还以上述的数据集为例:T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},在**查找(2.1,3.1)**时,设置一个栈或者队列(search_path),来进行存储通过KD树到达的节点,从下图可知,search_path中的结点为<(7,2),(5,4),(2,3)>,从中取出(2,3)为当前最佳结点nearest,dist(距离)为0.141
在这里插入图片描述
然后回溯至(5,4),以(2.1,3.1)为圆心,dist=0.141为半径画一个圆,并不和超平面y=4相交,如下图,所以不必跳到结点(5,4)的右子空间去搜索,因为右子空间中不可能有更近的样本点了。于是再回溯到(7,2),同理,以(2.1,3.1)为圆心,以dist=0.141为半径画一个圆并不和超平面x=7相交,所以也不用跳到结点(7,2)的右子空间去搜索。至此,search_path为空,结束整个搜索,返回nearest(2,3)作为(2.1,3.1)的最近邻点,最近距离为0.141:
在这里插入图片描述

查找点(2,4.5),在(7,2)处测试到达(5,4),在(5,4)处测试到达(4,7),然后search_path中的结点为<(7,2),(5,4),(4,7)>,从中取最后一个作为当前最佳节点,dist=3.202。回溯至(5,4),以(2,4.5)为圆心,2.302为半径画一个元与y=4相交,所以跳到(5,4)的左子空间去搜索,所以要将(3,2)加入到search_past中,现在seach_past中的节点<(7,2),(2,3)>,另外,上一次回溯(5,4)与(2,4.5)的距离为3.04<3.202,所以把(5,4)赋给nearest,dist=3.04。继续回溯到(2,3),由于(2,3)是叶子节点(最后一个判断点),直接判断(2,3)是否离(2,4.5)更近,得到距离为1.5,所以更新nearest为(2,3),dist=1.5,同理,回溯到(7,2),以(2,4.5)为圆心,1.5为半径画一个圆不和超平面x=7相交,所以不用跳到(7,2)的右子空间去搜索,演示如下图:
在这里插入图片描述
感谢大家的阅读,后续更新请关注本专栏…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白白净净吃了没病

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值