KNN算法:线性扫描的原理实现及结果

(2020.8.26)对程序调用进行了修改,经过测试可以得到结果。

K-最近邻算法(K - Nearest Neighbors,KNN)是一种基本分类与回归方法,可看做是最近邻算法(K=1)的一个延伸。
KNN基本思路是:选择未知样本在一定范围内确定个数的K个样本,该K个样本大多数属于某一类型,则未知样本判定为该类型

如何选择一个最佳的K值取决于数据。一般情况下,在分类时较大的K值能够减小噪声的影响,但会使类别之间的界限变得模糊。

看图说话:
待测样本(绿色圆圈)既可能分到红色三角形类,也可能分到蓝色正方形类。如果k取3,从图可见,待测样本的3个邻居在实线的内圆里,按多数投票结果,它属于红色三角形类。但是如果k取5,那么待测样本的最邻近的5个样本在虚线的圆里,按多数表决法,它又属于蓝色正方形类。在实际应用中,K先取一个比较小的数值,再采用交叉验证法来逐步调整K值,最终选择适合该样本的最优的K值。
图1

而我们在意的三个问题是:K 值的选取、距离度量、分类决策规则

一、K 值的选择
K 值的选择会对 K 近邻法的结果产生重大影响。

K 值较小】:相当于用较小邻域中的训练实例进行预测,模型的训练误差会减小,只有与输入实例较近的训练实例才会对预测结果起作用。

缺点:模型的泛化误差会增大,预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,K 值的减小就意味着整体模型变得复杂,容易发生过拟合。

K 值较大】:相当于用较大邻域中的训练实例进行预测。可以减少模型的泛化误差。

缺点:训练误差会增大。这时,与输入实例较远的训练实例也会对预测起作用,使预测发生错误。K 值的增大意味着整体的模型变得简单。

K = N】:无论输入实例是什么,都将简单地预测它属于在训练实例中最多的类。此时,模型过于简单,完全忽略训练实例中的大量有用信息。

在实际应用中,K 值一般取一个比较小的数值(sklearn 中的 KNeighborsClassifier 默认 k 值为 5)、通常采用交叉验证法来选取最优的 K 值。

二、距离度量
特征空间中两个实例点的距离是两个实例点相似程度的反映。

K 近邻模型的特征空间一般是 n 维实数向量空间 Rn ,使用的距离是欧氏距离,但也可以是更一般的 Lp距离(范数)或 Minkowski 距离。
范数
在这里插入图片描述
p=1:称为曼哈顿距离(Manhattan distance),或城市街区距离(Cityblock distance)
p=2:称为欧式距离(Euclidean distance),又简称 2 范数
p=无穷时,为切比雪夫范数。

>>> import numpy as np
>>> x1, x2 = np.array([3, 2]), np.array([1, 4])
>>> # 欧式距离
... np.linalg.norm(x1 - x2, 2)
2.8284271247461903
>>> # 曼哈顿距离
... np.linalg.norm(x1 - x2, 1)
4.0
>>> # 切比雪夫距离
... np.linalg.norm(x1 - x2, np.inf)
2.0

三、分类决策规则
K 近邻法中的分类决策规则往往是多数表决,即由输入实例的 K 个邻近训练实例中的多数类决定输入实例的类。

例如下图,按照当前实例的 5 个邻近训练实例中有 3 个属于正类,2 个属于负类,那么该实例最终被预测为正类。
在这里插入图片描述


K 近邻法实现
K 近邻法有两种实现方式:

1.线性扫描(linear scan):计算输入实例与每一个训练实例的距离。优点是简单易实现,但训练集很大时,计算非常耗时,不可行。
2.kd 树(K-dimension tree):利用 kd 树可以省去对大部分数据点的搜索,从而减少搜索的计算量。

本文讲解线性扫描的实现法

具体:
1.线性扫描的思路:计算目标点与已有的全部点之间的距离,然后从中选择距离最短的 k 个近邻点,并获得这些点的类别信息。最后根据这些点的类别信息判断目标点的类别。


必要的储备:
(1)sorted函数的一个小例子:
sorted函数:内建函数 sorted 方法返回的是一个新的 list,sorted() 函数对所有可迭代的对象进行排序操作。

栗子:d1记录了四个人的姓名和分数,其中[{‘name’:‘alice’, ‘score’:38}是字典的结构。下面代码目的是对d1先按照成绩降序排序,相同成绩的按照名字升序排序。

    d1 = [{'name':'alice', 'score':38}, {'name':'bob', 'score':18}, {'name':'darl', 'score':28}, {'name':'christ', 'score':28}]
    #d1记录了四个人的姓名和分数,其中[{'name':'alice', 'score':38}是字典的结构
    #下面对d1先按照成绩降序排序,相同成绩的按照名字升序排序. 有负号是降序
    d2 = sorted(d1, key=lambda x:(-x['score'], x['name']))
    print(d2)

运行结果:
在这里插入图片描述

(2)np.hstack:按水平方向(列顺序)堆叠数组构成一个新的数组

a = np.array([[1,2,3]])
a.shape
Out[11]:
(1, 3)

In [12]:
b = np.array([[
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值