文章目录

  • KNN 简介
  • KNN 三要素
    • 距离度量
    • k值的选择
    • 分类决策规则
  • KNN 实现
    • 1,构造kd树
    • 2,搜索最近邻
    • 3,预测
  • 用kd树完成最近邻搜索

K近邻算法(KNN)算法,是一种基本的分类与回归算法,本文只讨论解决分类问题的KNN算法。

KNN 简介

思想:给定一个训练数据集,对于新输入的样本,在训练集中找到与该样本最邻近的k个已知样本,这k个已知样本的多数属于某个类别,那么新输入的样本就属于这个类别。

如下图所示,假定使用欧氏距离作为度量方式,采样投票法决定类别,并且?表示待预测的样本,当k取1时,则变成了最近邻算法,对应的类别为★;当k取7时,类别为▲;可见k的取值对分类效果有比较大的影响。在实际应用中,k的取值一般不超过20。

该算法的优点是:

  1. 精度高
  2. 对异常值不敏感
  3. 无数据输入假定

缺点是:

  1. 计算复杂度高
  2. 空间复杂度高

KNN 三要素

KNN算法不具有显式的训练过程。距离度量(如欧氏距离)、k值以及分类决策规则(如投票表决)是KNN算法的三要素。在给定训练集合于三要素后,对于任何新输入的样本,它所属的类别是唯一确定的。下面对这三个要素展开讨论。

距离度量

在n维的特征空间中,距离反映的是两个点的相似程度。KNN 算法常用的距离度量为欧式距离,但也可以采用其他距离,比如更一般的 LpL_{p}Lp​距离,其中p为正整数:
Lp(xi,xj)=(∑l=1n∣xi(l)−xj(l)∣p)1pL_p(x_i, x_j)=\left(\sum_{l=1}^{n}{\left|x_{i}^{(l)}-x_{j}^{(l)}\right|^p}\right)^{\frac{1}{p}} Lp​(xi​,xj​)=(l=1∑n​∣∣∣​xi(l)​−xj(l)​∣∣∣​p)p1​
当p=1时,即为曼哈顿距离,也叫出租车距离,用以标明两个点在标准坐标系上的绝对轴距总和,如下图中的红色线条所示,蓝色和黄色为等价曼哈顿距离。

当p=2时,即为常见的欧氏距离,也就是直线距离,如上图的绿色线条所示。

不同距离度量确定的最近点是不同的,例如对于:
x1=(1,1),x2=(5,1),x3=(4,4)x_1=(1, 1), x_2 = (5,1), x_3 = (4,4) x1​=(1,1),x2​=(5,1),x3​=(4,4)
由于x1,x2x_1, x_2x1​,x2​只有一个坐标轴不同,所以无论p取多少,距离都为4。但是:
L1(x1,x3)=6,L2(x1,x3)=4.24L3(x1,x3)=3.78,L4(x1,x3)=3.57L_1(x_1, x_3)=6, L_2(x_1, x_3)=4.24\\ L_3(x_1, x_3)=3.78, L_4(x_1, x_3)=3.57 L1​(x1​,x3​)=6,L2​(x1​,x3​)=4.24L3​(x1​,x3​)=3.78,L4​(x1​,x3​)=3.57
也就是说当p大于等于3时,x1,x3x_1, x_3x1​,x3​ 之间距离最近。

k值的选择

k 值的选择对结果会产生重大影响。

如果选择较小的k值,那么相当于只用少数的训练样本完成预测。这样的预测结果对邻近的样本点非常敏感,一方面容易造成过拟合,另一方面容易受到恰巧是噪声的临近点的干扰。

如果选择较大的k值,那么距离较远的(不相似)的点也会对预测结果产生影响,容易使得预测结果发生错误。极端情况下,当k取样本的个数时,预测结果就是众数,完全忽略了训练样本中真正有效的信息。

实际应用中,k一般取较小的值,采用交叉验证的方法确定最优的k值。

分类决策规则

一般是以多数表决为决策规则,即通过投票决定最终的类别。

假设分类函数为:
f:Rn→{c1,c2,...,cK}f: R^n \rightarrow\{c_1, c_2,..., c_K\} f:Rn→{c1​,c2​,...,cK​}
对一个预测结果f(X)f(X)f(X)而言,误分类的概率为:
P(Y≠f(X))=1−P(Y=f(X))P(Y \ne f(X)) = 1-P(Y=f(X)) P(Y​=f(X))=1−P(Y=f(X))
假定KNN取最近邻的k个样本组成的集合Nk(x)N_k(x)Nk​(x)用于表决,设表决结果为cjc_jcj​,那么误分类的概率为:
1k∑xi∈Nk(x)I(yi≠ci)=1−1k∑xi∈Nk(x)I(yi=ci)\frac{1}{k}\sum_{x_i\in N_k(x)}{I(y_i\ne c_i)}=1-\frac{1}{k}\sum_{x_i\in N_k(x)}{I(y_i= c_i)} k1​xi​∈Nk​(x)∑​I(yi​​=ci​)=1−k1​xi​∈Nk​(x)∑​I(yi​=ci​)
要使得误分类概率最小,则需要1k∑xi∈Nk(x)I(yi=ci)\frac{1}{k}\sum_{x_i\in N_k(x)}{I(y_i= c_i)}k1​∑xi​∈Nk​(x)​I(yi​=ci​)最大,也就是cjc_jcj​ 应该是Nk(x)N_k(x)Nk​(x)中出现次数最多的类别。

KNN 实现

实现KNN算法时,主要问题是如何快速在训练样本中找到k个最近邻的点。

一种最简单的实现是线性扫描,每输入一个新的样本,就需要计算这个样本和所有训练样本的距离,进而找到最近的k个样本。这样计算过于耗时,在特征空间维数很高以及训练样本特别多时尤为明显。

为了提高搜索效率,可以考虑使用树来存储训练数据,例如使用kd树算法。kd树中的k表示存储k维空间数据的树结构,与KNN中的k意义不同。

kd树算法包括三个步骤:1,构造kd树。2,搜索最近邻。3,预测。

1,构造kd树

kd树是二叉树,表示对k维空间的一个划分。构造kd树的过程就是不断的用垂直于坐标轴的超平面来切分k维空间,构成一些列的k维超矩形区域。最终kd树的每一个节点对应于一个k维超矩形区域。

具体而言,KD树建树首先计算m个样本的n个特征的取值的方差,用方差最大的第k维特征nkn_knk​来作为根节点。假设特征nkn_knk​的中位数为nkvn_{kv}nkv​,那么对于所有第k维特征的取值小于nkvn_{kv}nkv​的样本,我们划入左子树,对于第k维特征的取值大于等于nkvn_{kv}nkv​的样本,我们划入右子树。对于左右两颗子树,则对未用于父节点划分的特征重复上面的操作,直到左右子树没有样本时终止。

举个例子,假设有二维样本6个,{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构建kd树的具体步骤为:

(1) 找到划分特征。x维度方差6.97 > y维度方差 5.37。所以选择第一个维度进行划分。

(2) 确定划分点。x维度数字为:2,4,5,7,8,9。可以取中位数为:5或者7,这里取7。于是划分超平面会经过(7,2)且垂直于坐标轴X。

(3) 确定左右子空间。由于划分超平面的确定,所以x<=7的样本{(2,3),(5,4),(4,7)}属于左子空间,x>=7的样本{(9,6),(8,1)}属于右子空间。

(3) 对未用于父节点划分的特征重复上面的操作。

最后得到的KD树如下:

2,搜索最近邻

给定目标点(2,4.5),要搜索其最近邻,首先要找到包含目标点的叶节点。具体而言,首先从根节点(7,2)出发,首先根据x=2 < x=7向左找到节点(5,4),继续跟进y=4.5 > y=4 向右找到(4,7),即与目标点最近的点为(4,7)。

以目标点(2,4.5)为圆心,以目标点到叶子节点(4,7)样本实例的距离3.202为半径,得到一个超球体。最近邻的点肯定在超球体的内部,如下图所示:

计算得到圆心到其父节点(5,4)的距离为3.041,所以最近邻点更新为(5, 4)。

继续查找在半径3.041内的点,发现父节点(5,4)的另一边的子空间和超球面有交集,所以还需要到(5,4)的左子空间内确定其中的点到目标点的距离是否更小。发现(2,3)节点的距离更小,最近邻点更新为(2,3),最近距离更新为1.5。

此时目标点区域父节点(5,4)的两个子空间都搜索完毕,需要继续搜索(5,4)的父节点的另一个子空间是否有更近的点。重复这个过程,直到遇到根节点后结束搜索,得到最近邻的点为(2,3)。

上面的过程总结如下:

当我们生成KD树以后,就可以去预测测试集里面的样本目标点了。对于一个目标点,我们首先在KD树里面找到包含目标点的叶子节点。以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最近邻的点一定在这个超球体内部。然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体是否和超球体相交,如果相交就到这个子节点寻找是否有更加近的近邻,有的话就更新最近邻。如果不相交那就简单了,我们直接返回父节点的父节点,在另一个子树继续搜索最近邻。当回溯到根节点时,算法结束,此时保存的最近邻节点就是最终的最近邻。

3,预测

理解最近邻点的搜索方法后,如果我们要查找最近邻的K个点,只需要在第一轮先找到最近邻点,然后在第二轮忽略这个最近邻的点,查找次最近邻的点。重复这个过程,直到找到了K个近邻的点。如果是KNN分类,预测为K个最近邻里面有最多类别数的类别。如果是KNN回归,用K个最近邻样本输出的平均值作为回归预测值。

用kd树完成最近邻搜索

输入:已构造的kd树,目标点x

输出: x的最近邻。

(1) 在kd树中找出包含目标点x的叶结点:从根结点出发,递归地向下访问kd树。若目标点x当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止。.

(2) 以找到的叶结点为“当前最近点”。

(3) 递归地向上回退,在每个父结点进行以下操作:

  1. 如果该结点保存的实例点比当前最近点距离目标点更近,则以该实例点为“当前最近点”。

  2. 当前最近点一定存在于该父结点的一个子结点对应的区域,即检查父结点的另一子结点对应的区域是否有更近的点。具体地,检查另一子结点对应的区域是否与以目标点为球心、以目标点与“当前最近点”间的距离为半径的超球体相交。

    如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点。接着,递归地进行最近邻搜索。

    如果不相交,向上回退。

(4) 当回退到根结点时,搜索结束。最后的“当前最近点”即为x的最近邻点。

如果实例点是随机分布的,kd树搜索的平均计算复杂度是O(logN),这里N是训练实例数。kd树更适用于训练实例数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时,它的效率会迅速下降,几乎接近线性扫描。

参考文章:

《统计学习方法 第二版》

K近邻法(KNN)原理小结

基于KD树的K近邻算法(KNN)算法相关推荐

  1. 基于kd树的k近邻算法——KNN

    1.简介 k近邻算法是机器学习中一种基本的分类与回归算法,对你没听错k近邻算法不仅可以用来做分类,还可以用于回归,英文全称为k-Nearest Neighbor简称k-NN.k近邻算法属于一种有监督学 ...

  2. 机器学习基础(四十三)—— kd 树( k 近邻法的实现)

    实现 k 近邻法时,主要考虑的问题是如何对训练数据进行快速 k 近邻搜索,这点在如下的两种情况时,显得尤为必要: (1)特征空间的维度大 (2)训练数据的容量很大时 k 近邻法的最简单的实现是现行扫描 ...

  3. 机器学习算法总结之K近邻(KNN)

    写在前面 K近邻(K-nearest neighbor,k-nn)是一种常用的机器学习监督学习方法,可用于分类和回归问题.其工作机制为:给定测试样本,基于某种距离度量找出训练集中与其最靠近的K个训练样 ...

  4. 一文搞懂k近邻(k-NN)算法(一)

    原文链接 一文搞懂k近邻(k-NN)算法(一) 前几天和德川一起在学习会上讲解了k-NN算法,这里进行总结一下,力争用最 通俗的语言讲解以便更多同学的理解. 本文目录如下: 1.k近邻算法的基本概念, ...

  5. K近邻(KNN)算法是基于实例的算法,如果训练样本数量庞大,预测的时候挨个计算距离效率会很低下,如何破解?

    K近邻(KNN)算法是基于实例的算法,如果训练样本数量庞大,预测的时候挨个计算距离效率会很低下,如何破解? K近邻(KNN)是最简单的算法之一,它计算预测样本与训练数据集中每个数据点之间的距离,并找到 ...

  6. K近邻(KNN)算法总结

    文章目录 一.KNN原理 二.KNN的三要素 2.1 k值的选择 2.2 距离度量 2.3 分类决策规则 三.KNN算法实现 3.1 KNN算法蛮力实现 3.2 KD树实现 3.3 球树实现 四.KN ...

  7. 机器学习算法与Python实践之(二)k近邻(KNN)

      机器学习算法与Python实践之(二)k近邻(KNN) (基于稀疏矩阵的k近邻(KNN)实现) 一.概述 这里我们先来看看当我们的数据是稀疏时,如何用稀疏矩阵的特性为KNN算法加速.KNN算法在之 ...

  8. 基于稀疏矩阵的k近邻(KNN)实现

    基于稀疏矩阵的k近邻(KNN)实现 zouxy09@qq.com http://blog.csdn.net/zouxy09 元旦了!要跨入2015了!呵呵,忙了挺久,没有更新博客了,博客也悄悄地蒙上了 ...

  9. 介绍一下K近邻(KNN)算法,KNeighbors和RadiusNeighbors的差异是什么?各有什么优势?

    介绍一下K近邻(KNN)算法,KNeighbors和RadiusNeighbors的差异是什么?各有什么优势? K近邻(KNN)算法 近邻(Nearest Neighbor)算法既可以用于监督学习(分 ...

最新文章

  1. 用Scrapy爬虫框架爬取食品论坛数据并存入数据库
  2. 多视图立体匹配论文分享:P-MVSNet
  3. conda env环境配置
  4. Andorid的Linux基础教学之四 进程的生死存亡
  5. Python回顾与整理1:Python基础
  6. [译]Speeding up your PHP scripts
  7. c++11-Variadic Templates
  8. dbunit使用_摆脱困境:在DbUnit数据集中使用空值
  9. Springboot源码——应用程序上下文分析
  10. 感恩节专宠有礼,送3本技术好书
  11. 吐槽Javascript系列三:数组的陷阱
  12. 操作系统实验报告-多线程编程解决进程间同步和互斥问题
  13. vue-JsMind思维导图实现(包含鼠标右键自定义菜单)
  14. 可调稳压电源lm317实验报告_LM317可调稳压电源实训实验分析讲解.doc
  15. 5号字对应的数字字号_五号字体是多少磅的?
  16. python游戏开发keydown_pygame.KEYDOWN移动对象
  17. Docker - 常见操作命令篇
  18. 达索系统基于3DEXPERIENCE平台开发工具介绍
  19. 如何在小程序中直接跳到关注微信公众号页面
  20. 手机上有哪些超棒超实用的APP让你觉得相见恨晚

热门文章

  1. 关于高并发的一些笔记
  2. colab加载google drive并且调试时跳过不运行
  3. 计算机系统 程序和指令
  4. Arduino总结一
  5. 为什么不能用python_为什么我不能用python加入这个线程?
  6. python怎么导入大小字母_isort-用于对python导入的库按照字母进行排序的工具
  7. STM32F2xx DMA Controllers
  8. C语言结构体实现类似C++的构造函数
  9. 理解数据类型与数学运算:求和、温度转换2
  10. string数组批量转换成Int数组