K-近邻算法
00 min
2024-4-23
K-近邻算法(K-Nearest Neighbors,简称KNN算法)是一种用于分类和回归的监督学习算法。其工作原理:给定测试样本,基于某种距离度量找出练集中 与其最靠近的个训练样本,然后基于这个"邻居"的信息来进行预测在分类任务中可使用"投票法" ,即选择这个样本中出现最多的类别标记作为预测结果;在回归任务中时使用"平均法" ,即将这个样本的实值输出标记平均值作为预测结果;还可基于距离远近进行加权平均或加权投票,距离越近的样本权重越大。

基本原理

为了更直观的理解KNN算法的逻辑,下面用KNN算法通过1~9个样本来预测样本10的电影的电影类型:
序号
电影名称
搞笑镜头
拥抱镜头
打斗镜头
电影类型
距离
k=5时
1
功夫熊猫
39
0
31
喜剧片
21.47
2
叶问3
3
2
65
动作片
52.01
3
伦敦陷落
2
3
55
动作片
43.42
4
代理情人
9
38
2
爱情片
40.57
5
新步步惊心
8
34
17
爱情片
34.44
6
谍影重重
5
2
57
动作片
43.87
7
功夫熊猫
39
0
31
喜剧片
21.47
8
美人鱼
21
17
5
喜剧片
18.55
9
宝贝当家
45
2
9
喜剧片
23.43
10
唐人街探案
23
3
17
——
为了预测样本10的电影类型,需要将其和其他9个样本的”距离“(相似度)分别计算出来,让后将结果按照从小到大排列,选取k个”距离“较小的邻近样本,然后样本10的电影类型即为这k个邻近样本中票数最多的电影类型。那么,问题来了,如何计算两个样本之间的”距离“呢?
两点之间的直线距离(欧式距离)公式为:
那么同样可以根据这个公式类推,通过两个样本的对应特征值来计算样本间距离。那么唐人街探案和伦敦陷落的“距离”为
同上上述方法获得样本10和其他样本的距离之后,设定参数k=5,则从样本集中选取5个距离较小的样本,其中三个是喜剧片,两个为爱情片,那么样本10预测的电影类型为喜剧片。

K值分析

  • K值过小:用较小的邻域中的训练实例进行预测,容易受到异常点影响,导致可能发生过拟合。
  • K值过大:用较大邻域中的训练实例进行预测,容易受到样本均衡的影响,K值的增大意味着整体的模型变得简单,导致可能发生欠拟合。
  • 如何对K超参数进行调优?(这将在后面的内容讲解)
    • 交叉验证
    • 网格搜索

KNN应用

  • 算法思想:若一个样本在特征空间中的 k 个最相似的样本大多数属于某一个类别,则该样本也属于这个类别
  • 相似性:欧式距离
  • 解决问题:分类问题、回归问题
    • 分类:
      • 计算未知样本到每一个训练样本的距离
      • 将训练样本根据距离大小升序排列
      • 取出距离最近的 K 个训练样本
      • 进行多数表决,统计 K 个样本中哪个类别的样本个数最多
      • 将未知的样本归属到出现次数最多的类别
    • 回归:
      • 计算未知样本到每一个训练样本的距离
      • 将训练样本根据距离大小升序排列
      • 取出距离最近的 K 个训练样本
      • 把这个 K 个样本的目标值计算其平均值
      • 作为将未知的样本预测的值

KNN算法API使用

KNN算法用于分类和回归两个问题,两者导入的类有所不同。
 

分类问题

  • sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
    • n_neighbors:int,可选(默认= 5),n_neighbors查询默认使用的邻居数K

回归问题

  • sklearn.neighbors.KNeighborsRegressor(n_neighbors=5)

距离度量(了解)

在KNeighborsRegressor回归算法函数中,有两个参数:p=2, metric='minkowski', 用于表示回归算法函数具体使用什么距离度量方法作为KNN算法的相似性指标,默认为欧式距离(Euclidean Distance)

欧式距离

直观的距离度量方法,两个点在空间中的直线距离。
二维平面上点间的欧式距离:
n维平面上点间的欧式距离:

曼哈顿距离

曼哈顿距离(Manhattan Distance)也称为“城市街区距离”(City Block distance),曼哈顿城市特点:横平竖直
notion image
二维平面上点间的曼哈顿距离:
n维平面上点间的曼哈顿距离:

切比雪夫距离 Chebyshev Distance

国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?这个距离就叫切比雪夫距离。
notion image
二维平面上点间的切比雪夫距离:
n维平面上点间的切比雪夫距离:
例子: ABCD四点 X=[ [1,1], [2,2], [3,3], [4,4] ] ,计算AB AC AD BC BD曼哈顿距离,经计算得: AB =max(|2−1|, |2−1|) = 1, d = 1 2 3 1 2 1

闵可夫斯基距离 Minkowski Distance

闵氏距离不是一种新的距离的度量方式,而是对多个距离度量公式的概括性的表述。
n维平面上点间的闵可夫斯基距离定义为
其中p是一个变参数:
  • 当 p=1 时,就是曼哈顿距离;
  • 当 p=2 时,就是欧氏距离;
  • 当 p→∞ 时,就是切比雪夫距离
根据p的不同,闵氏距离可表示某一类种的距离。
 

特征预处理(归一化和标准化)

归一化和标准化是特征工程中的一个重要环节。主要应用于:
  • 涉及多个特征一起进行计算, 比如计算欧式距离
  • 特征的取值范围, 差异较大 (量纲不统一)
请看下面例子:
编 号
身高 cm
体重 kg
视力 0.2-2.0
健康 状况
1
170
67
1.5
1
2
171
80
0.8
2
3
175
70
1.5
1
4
176
68
1.2
1
5
180
80
1.8
1
6
181
90
0.6
2
7
175
75
0.8
现有6个样本数据,需要通过6个样本的特征向量(身高, 体重, 视力)来对样本7的健康状况进行评估(1表示健康,2表示不健康)。那么按照上节内容通过KNN算法来预测样本7的目标值的时候,视力项的特征值相对于身高和体重显然不在一个数量级,计算的结果中视力的特征值对结果的影响微乎其微。
为了避免多个特征值间的数量级不在同一个水平,需要使用到归一化或者标准化。

归一化

通过对原始数据进行变换把数据映射到【mi,mx】区间(默认为[0,1])之间
notion image
代码实现:
  • sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
    • feature_range: 缩放区间,默认为(0, 1)
  • fit_transform(X) 将特征进行归一化缩放
  • 如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
  • 应用场景:最大值与最小值非常容易受异常点影响, 鲁棒性较差,只适合传统精确小数据场景

标准化

通过对原始数据进行标准化,转换为均值为0标准差为1的标准正态分布的数据.
其中, mean为特征值的平均值; 为特征值的标准差
代码实现:
  • sklearn.preprocessing.StandardScaler()
  • fit_transform(X) 将特征进行归一化缩放
  • 如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大
  • 应用场景:适合现代嘈杂大数据场景。(以后就是用你了)

案例:利用KNN算法对鸢尾花分类


超参数选择及验证

交叉验证

上面鸢尾花的案例中,我们只使用了一份测试集对模型进行测试,这样的操作方式数据集并没有得到充分利用,训练出的模型也并不是充分可信的。
交叉验证是一种数据集的分割方法,将训练集划分为 n 份,分别拿其中一份做验证集(测试集)、其他n-1份做训练集。例如当数据集划分为cv = 4份时:
  1. 第一次:把第一份数据做验证集,其他数据做训练
  1. 第二次:把第二份数据做验证集,其他数据做训练
  1. ... 以此类推,总共训练4次,评估4次。

网格搜索

同样在鸢尾花案例中,可调整的参数包括:k(领居的个数)和p(距离测量的方式),对于给定不同的参数组合,训练得出来的模型准确率可能有所不同,能否将的所有可能组合都验证一下,得出最佳的组合,以提高模型的准确率?
网格搜索就是把所有要尝试的参数组合, 都遍历一圈, 使用数据来训练对应模型, 通过测试集表现来找到最佳的参数组合。
 
交叉验证和网格搜索通常强有力的组合在一起使用
  • 交叉验证解决模型的数据输入问题(数据集划分)得到更可靠的模型
  • 网格搜索解决超参数的组合
  • 两个组合再一起形成一个模型参数调优的解决方案

交叉验证网格搜索API使用

  • sklearn.model_selection.GridSearchCV(estimator, para_grid=None, cv=None)
    • estimator:学习器对象
    • param_grid:学习器对象中的参数,字典形式传惨;例如:{'n_neighbors':[4,5,7,9]}
    • cv:int,指定几折交叉验证

鸢尾花案例 — 交叉验证网格搜索

 

利用KNN算法实现手写数字识别

  • 已知数据
    • MNIST手写数字识别
    • 1999年发布,成为分类算法基准测试的基础
    • MNIST仍然是研究人员和学习者的可靠资源
  • 需求
    • 从数万个手写图像的数据集中正确识别数字
  • 数据介绍
    • 数据文件 train.csv 和 test.csv 包含从 0 到 9 的手绘数字的灰度图像。
    • 每个图像高 28 像素,宽28 像素,共784个像素。
    • 每个像素取值范围[0,255],取值越大意味着该像素颜色越深
    • 训练数据集(train.csv)共785列。第一列为 "标签",为该图片对应的手写数字。其余784列为该图像的像素值
    • 训练集中的特征名称均有pixel前缀,后面的数字([0,783])代表了像素的序号
    • notion image