kNN(k-Nearest Neighbours)原理详解

1 kNN简介

  kNN(k- Nearest Neighbor)法即k最邻近法,最初由 Cover和Hart于1968年提出,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一,它的适用面很广,并且在样本量足够大的情况下准确度很高,多年来得到了很多的关注和研究。
  它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

2 图解kNN基本原理

  假设有三种兔子,第一种兔子叫作绿兔(Green),它们的平均身高是 50厘米,平均体重 5公斤。选取100个样本,分别测量它们的身高和体重,画在坐标图上,用绿色方块表示。

在这里插入图片描述  第二种兔子叫蓝兔(blue),它们体型比较小,平均身高是 30厘米,平均体重是 4公斤。同样,选取100个样本,分别测量它们的身高和体重,并将它们画在同一个坐标图上,用蓝色三角表示。

在这里插入图片描述  最后一种兔子叫黄兔(yellow),它们的平均身高45厘米,但体重较轻,平均只有2.5公斤。100只黄兔的数据用黄色圆圈表示。

在这里插入图片描述  在这些数据中,(身高,体重)的二元组叫做特征(features),兔子的品种则是分类标签(class label)。我们想解决的问题是,给定一个未知分类的新样本的所有特征,通过已知数据来判断它的类别。

  现在假设有一只兔子R,想要确定它属于绿兔、蓝兔和黄兔中的哪一类,应该怎么做呢?按照最普通的直觉,应该在已知数据里找出几个和我们想探究的兔子最相似的几个点,然后看看那些兔子都是什么个情况;如果它们当中大多数都属于某一类别,那么兔子R大概率也就是那个类别了。

  为了确定兔子R属于哪一类,首先测量出其身长为 40 厘米,体重 2.7 公斤,为了直观展示,将其画在上述同一坐标系中,用红色五角星表示。
在这里插入图片描述

  现在预设一个整数k,寻找距离兔子R最近的k个数据样本进行分析。kNN 算法如何对这次观测进行分类要取决于k的大小。直觉告诉我们兔子R像是一只黄兔,因为除了最近的蓝色三角外,附近其他都是黄色圆圈。的确,如果设 k = 15,算法会判断这只兔子是一只黄兔。但是如果设 k = 1,那么由于距离最近的是蓝色三角,会判断兔子R是一只蓝兔。

  如果按照15NN和1NN的方法对这个二维空间上的每一个点进行分类,会形成以下的分割:

在这里插入图片描述在这里插入图片描述  在两组分类中,1NN 的分类边界明显更“崎岖”,但是对历史样本没有误判;而 15NN 的分类边界更平滑,但是对历史样本有发生误判的现象。选择k的大小取决于对偏差和方差之间的权衡。

1)k近邻算法中k的选取

  如果我们选取较小的k值,那么就会意味着我们的整体模型会变得复杂,容易发生过拟合!假设我们选取k=1这个极端情况,并且有训练数据和待分类点如下图:
在这里插入图片描述
  上图中有俩类,一个是黑色的圆点,一个是蓝色的长方形,现在我们的待分类点是红色的五边形。根据我们的k近邻算法步骤来决定待分类点应该归为哪一类。我们由图中可以得到,五边形离黑色的圆点最近,k又等于1,因此,我们最终判定待分类点是黑色的圆点。

  由这个处理过程我们很容易能够感觉出问题了,如果k太小了,比如等于1,那么模型就太复杂了,我们很容易学习到噪声,也就非常容易判定为噪声类别,而在上图,如果,k大一点,k等于8,把长方形都包括进来,我们很容易得到我们正确的分类应该是蓝色的长方形!如下图:
在这里插入图片描述
  所谓的过拟合就是在训练集上准确率非常高,而在测试集上准确率低,经过上例,我们可以得到k太小会导致过拟合,很容易将一些噪声(如上图离五边形很近的黑色圆点)学习到模型中,而忽略了数据真实的分布!

  如果我们选取较大的k值,就相当于用较大邻域中的训练数据进行预测,这时与输入实例较远的(不相似)训练实例也会对预测起作用,使预测发生错误,k值的增大意味着整体模型变得简单。

  我们想,如果k=N(N为训练样本的个数),那么无论输入实例是什么,都将简单地预测它属于在训练实例中最多的类。这时,模型是不是非常简单,这相当于你压根就没有训练模型呀!直接拿训练数据统计了一下各个数据的类别,找最大的而已!这好像下图所示:
在这里插入图片描述
  我们统计了黑色圆形是8个,长方形个数是7个,那么,如果k=N,我就得出结论了,红色五边形是属于黑色圆形的。这个时候,模型过于简单,完全忽略训练数据实例中的大量有用信息,是不可取的。

  综上分析,k值既不能过大,也不能过小,在我举的这个例子中,我们k值的选择,在下图红色圆边界之间这个范围是最好的,如下图:
在这里插入图片描述  注:这里只是为了更好让大家理解,真实例子中不可能只有两维特征,但是原理是一样的,我们就是想找到较好的k值大小。那么我们一般怎么选取呢?常用的方法是从k=1开始,使用检验集估计分类器的误差率。重复该过程,每次K增值1,允许增加一个近邻。选取产生最小误差率的K。一般k的取值不超过20,上限是 n n n的开方,随着数据集的增大,K的值也要增大。(李航博士书上讲到,我们一般选取一个较小的数值,通常采取交叉验证法来选取最优的k值。也就是说,选取k值很重要的关键是实验调参,类似于神经网络选取多少层这种,通过调整超参数来得到一个较好的结果)。

2)距离函数

  我们在上面的例子中把一个很重要的概念隐藏了起来,选择一个数量k 还只是小问题,更重要的是距离的计算方法。毕竟,当我们说“最近的k个点”时,这个“近”是怎么衡量的?

  在数学中,一个空间上距离的严格定义如下:
  设 M M M为一个空间, M M M上的一个距离函数 d : M × M → R d : M × M → \mathbb{R} d:M×MR,满足:
   ∙ ∙ d ( x , y ) ≥ 0 d(x,y)≥0 d(x,y)0  ∀ x , y ∈ M ∀x,y∈M x,yM
   ∙ ∙ d ( x , y ) = 0 ⟺ x = y d(x,y)=0 ⟺ x=y d(x,y)=0x=y
   ∙ ∙ d ( x , y ) = d ( y , x )   ∀ x , y ∈ M d(x,y)=d(y,x)  ∀x,y∈M d(x,y)=d(y,x) x,yM
   ∙ ∙ d ( x , z ) ≤ d ( x , y ) + d ( y , z )   ∀ x , y , z ∈ M d(x,z)≤d(x,y)+d(y,z)  ∀x,y,z∈M d(x,z)d(x,y)+d(y,z) x,y,zM
  两个点 x , y x,y x,y 之间的距离就是 d ( x , y ) d(x,y) d(x,y)
  我们一般最常用的距离函数是欧氏距离,也称作 L 2 L_{2} L2距离。如果 x = ( x 1 , x 2 , … , x n ) x=(x_{1},x_{2},…,x_{n}) x=(x1,x2,,xn) y = ( y 1 , y 2 , … , y n ) y=(y_{1},y_{2},…,y_{n}) y=(y1,y2,,yn) n n n维欧式空间 R n \mathbb{R}^{n} Rn上的两个点,那它们之间的 L 2 L_{2} L2距离是:
d 2 ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 (1) d_{2}(x,y)=\sqrt{\sum_{i=1}^{n}(x_{i}-y_{i})^{2}} \tag{1} d2(x,y)=i=1n(xiyi)2 (1)
   L 2 L_{2} L2是更普遍的 L p L_{p} Lp距离在 p = 2 p = 2 p=2 时的特例。 L p L_{p} Lp距离的函数 d p d_{p} dp定义如下:对于 1 ≤ p < ∞ 1\leq p< \infty 1p<,有:
d p ( x , y ) = ( ∑ i = 1 n ∣ x i − y i ∣ p ) 1 p (2) d_{p}(x,y)=\left(\sum_{i=1}^{n}|x_{i}-y_{i}|^{p}\right)^{\frac{1}{p}} \tag{2} dp(x,y)=(i=1nxiyip)p1(2)
  还有 L ∞ L_{\infty } L距离:
d ∞ ( x , y ) = m a x i = 1 , 2... , n ∣ x i − y i ∣ (3) d_{\infty }(x,y)=\underset{i=1,2...,n}{max}|x_{i}-y_{i}| \tag{3} d(x,y)=i=1,2...,nmaxxiyi(3)
  在实际应用中,距离函数的选择应该根据数据的特性和分析的需要而定,本篇就不进行更深入的探讨,一般情况下使用最常用的 L 2 L_{2} L2函数即可。

3)归一化处理

  【注意】使用 kNN 时需要根据特征数据的取值区间来调整坐标轴的比例,这个做法叫作标准化或者归一化。为什么要这么做呢?拿上面的例子来说,一只兔子的身长(cm)数值平均是它的体重(kg)的 10倍左右,如果我们在这组数值上直接使用 L 2 L_{2} L2距离函数的话就会导致横轴的距离比重明显放大,分类结果也不合理,如下图所示:

在这里插入图片描述
  如果把坐标轴成其他的单位,比如毫米和吨,并用相应的新数值来计算距离,又会得到完全不同的分类标准。甚至,在极端情况下,如果身高用纳米并且体重用吨计量,那么相比之下身高的数值会奇高无比,以至于两点之间的距离是完全由身高决定的,体重则没有任何权重。为了解决这个问题,我们应该在计算距离时把所有坐标轴进行归一化。
  在之前的例子中,由于横轴数值大约是竖轴的 10 倍左右,所以我们将横轴(身高)的数值压缩 10倍,即计算距离时使用:
d ( ( x 1 , x 2 ) , ( y 1 , y 2 ) ) = ( x 1 10 − y 1 10 ) 2 + ( x 2 − y 2 ) 2 (4) d((x_{1},x_{2}),(y_{1},y_{2}))=\sqrt{(\frac{x_{1}}{10}-\frac{y_{1}}{10})^{2}+(x_{2}-y_{2})^{2}} \tag{4} d((x1,x2),(y1,y2))=(10x110y1)2+(x2y2)2 (4)
就可以得出合理的 kNN 分类。
  一般来说,假设进行 kNN 分类使用的样本的特征是 { ( x i 1 , x i 2 , . . . , x i n ) } i = 1 m \left \{ \left ( x_{i1},x_{i2},...,x_{in} \right ) \right \}_{i=1}^{m} {(xi1,xi2,...,xin)}i=1m,取每一轴上的最大值减最小值:
M j = m a x i = 1 , 2 , . . . , m ( x i j ) − m i n i = 1 , 2 , . . . , m ( x i j ) (5) M_{j}=\underset{i=1,2,...,m}{max}\left ( x_{ij} \right )-\underset{i=1,2,...,m}{min}\left ( x_{ij} \right ) \tag{5} Mj=i=1,2,...,mmax(xij)i=1,2,...,mmin(xij)(5)
并且,在计算距离时将每一个坐标轴除以相应的 M_{j}以进行归一化,即:
d ( ( y 1 , . . . , y n ) , ( z 1 , . . . , z n ) ) = ∑ j = 1 n ( y j M j − z j M j ) 2 (6) d((y_{1},...,y_{n}),(z_{1},...,z_{n}))=\sqrt{\sum_{j=1}^{n}\left ( \frac{y_{j}}{M_{j}}-\frac{z_{j}}{M_{j}} \right )^{2}} \tag{6} d((y1,...,yn),(z1,...,zn))=j=1n(MjyjMjzj)2 (6)
便可以规避坐标轴比例失衡的问题。

4)概率kNN

  上面的kNN算法返回的是对一组特征的绝对分类,告诉我们这只兔子被判断为哪一个类别。可有时我们并不想知道一个确切地分类,而想知道它属于某个分类的概率是多大。比如我们发现一只身长 37厘米,体重 4.84公斤的小兔兔,在下图五角星的位置。
在这里插入图片描述

  这只兔子的特征数据在绿兔和蓝兔的分界处,机器不论判断它属于哪个类别都很有可能是错的。这时,类似“它有一半可能性是绿兔,一半可能性是蓝兔”的反馈会更有意义。
  为了这个目的,我们同样找出距离问题特征最近的 k k k个样本,但与其寻找数量最多的分类,我们统计其中每个类别的分别有多少个,再除以 k k k得到一个属于每一个类别概率值。比如在上面的图里,距离五角星最近的 15个样本中,有 8只绿兔和 7 只蓝兔,由此判断:它有 53% 的可能性是绿兔,47% 的可能性是蓝兔,0%的可能性是黄兔。
  在整个二维空间中的每一个点上进行概率 kNN 算法,可以得到每个特征点是属于某个类别的概率热力图,图中颜色越深代表概率越大。

在这里插入图片描述

15NN 绿兔的概率
在这里插入图片描述
15NN 蓝兔的概率

在这里插入图片描述

15NN 黄兔的概率

  相比于绝对的分类,这些概率的计算会给我们更有效的表述以及更多的应用空间。

3 kNN算法总结

  根据上述对kNN算法原理的解析,可以总结出其实现主要包含以下几个步骤:
  对于一组训练样本以及一个测试样本,
  (1)计算已知类别数据集中的点与当前点之间的距离;
  (2)按照距离递增次序排序;
  (3)选取与当前点距离最小的k个点;
  (4)确定前k个点所在类别的出现频率;
  (5)返回前k个点出现频率最高的类别作为当前点的预测分类。
  kNN算法作为一种较简单的算法,它的不足之处在于:
  (1)没有明显的训练过程,它是“懒惰学习”的典型代表,它在训练阶段所做的仅仅是将样本保存起来,如果训练集很大,必须使用大量的存储空间,训练时间开销为零;
  (2)必须对数据集中每个数据计算距离值,实际中可能非常耗时。
  由于上述的不足,为了提高kNN搜索的速度,可以利用特殊的数据存储形式来减少计算距离的次数。kd树就是一种以二叉树的形式存储数据的方法。kd树就是对k维空间的一个划分。构造kd树相当于不断用垂直于坐标轴的超平面将k维空间切分,构成一系列k维超矩阵区域。kd树的每一个节点对应一个超矩阵区域。后续文章讲详细介绍kd树的原理及算法实现。

参考资料
https://www.joinquant.com/view/community/detail/a98b7021e7391c62f6369207242700b2
https://zhuanlan.zhihu.com/p/25994179

  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Roar冷颜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值