- 可用于分类与回归
- 输入为实例特征向量,输出为类别,可以是多分类
- 没有显示的学习过程,假设给定一个有监督的训练集,新的实例根据最近k个实例的类别多数表决决定属于哪一类
- 利用训练数据对特征空间划分
- 三要素:k值、距离度量、分类规则
算法
输入:
训练集:
为输入实例特征向量
为实例类别;
待分类的实例x。
输出
实例x所属类别y
- 用给定的距离度量,在T中找出x最近的k个实例,涵盖这k个实例点的邻域为
- 在中根据分类规则决定x的类别y
为指示函数,时 为1,否则为0
最近邻算法
k =1 的特殊情形
knn模型三要素
模型
- 当训练集、距离度量、k值、分类规则确定时,对任一新实例x,所属类唯一确定
- 三要素将特征空间划分为子空间,每个空间确定所属类
- 特征空间中,每个实例x与空间中距离自己更近的所有点组成一个区域:单元(cell),对特种空间形成一种分割,实例的y作为单元的类别,这是最近邻
距离度量
距离是实例相似度反映
特征空间一般是n维实数向量空间 ,使用欧氏距离,也可以是更一般的Lp距离(minkowski距离)
设 , ,xi 和xj 的Lp距离为:
其中p >=1
欧氏距离(p=2)
曼哈顿距离(p=1)
p为正无穷时,是x 各坐标最大值
k值选择
- k值对knn算法结果有重大影响
- k较小时,近似误差会减小(因为特别远的实例不会算进来),但估计误差会增大(对近邻实例较敏感,例如噪声)。模型变复杂,易过拟合
- k较大时,近似误差增大(较远的不相似点也会算进来),估计误差减小。模型变简单
- k=N时,忽略了训练集中有用信息,不可取;
- k一般取较小值,用交叉验证法确定最优k
分类决策规则
多数表决
解释:分类函数为 ,损失函数为0-1损失,误分类概率为:
给定实例 x,k 邻域 , 若该邻域类别为 ,那么误分类概率(经验风险):
就要使: 最大
k近邻算法实现之 kd 树
当样本点比较多,搜索k近邻变得困难,于是有了kd树
- kd是一种树形结构,用于存储k维空间实例点并进行快速检索
- 是二叉树,表示k维空间一个划分
- 构造过程是初始化所有节点在根节点,选择坐标轴与其上一个切分点,用垂直于坐标轴的超平面将当前超矩形空间切分,实例划分到两个区域,持续此过程直到子区域(树节点)没有实例时终止
平衡kd树
输入: ,
输出:kd树
步骤:依次选择坐标轴进行切分,切分点为所在轴的中位数。平衡kd树未必是最优
- 构造根节点,是包含T的超矩形
- 以 为轴,所有实例 坐标中位数为切分点,将根节点超矩形切分为两个子区域(深度为1的左右子节点),左子节点分到 小于切分点的实例,右子节点分到 大于切分点的实例 , 等于切分点的实例保留在根节点。
- 重复,对深度为j的节点,选择 为坐标轴, ,切分方法同2
- 直到两个子区域没有实例点终止
根据以下数据集构建平衡kd树
空间划分
kd树的搜索
以最近邻为例,先找到包含目标点的叶节点,从该节点出发,在回溯到父节点过程中,不断寻找最近邻的点
步骤:
- 找到包含目标点x的叶节点:从根节点触发,当x小于切分点就往左子节点查找,否则往右子节点,知道叶节点
- 以改叶节点为当前最近邻
- 递归向上回溯,在每个节点node重复:
- 若node节点的实例距离x更近,则作为x的当前最近邻
- x当前最近邻一定在node的一个子节点对应的区域,检查node另一个子节点所在区域是否有更近的点,即另一子节点的区域是否与 以x为球心、x与当前最近邻近距离为半径的超球体相交;若相交,可能另一子节点存在距离x更近的点,移动到该子节点的区域继续;若不想交则向上回退。
- 回退到根节点时,当前最近邻为所得结果
若实例点随机分布,kd搜索平均复杂度为 ,N 为样本数,kd树更适合N 远大于维度k的搜索,当k 接近N时效率迅速下降。
优点:简单直观,对输入实例,归类为k个最近邻中的多数类
缺点:需对数据集仔细预处理,对超大规模数据集拟合时间较长、对高维数据集拟合欠佳、对稀疏数据无能为力(高维度、稀疏)(摘自《深入浅出python机器学习》)
练习:
- 测试不同k对应的空间划分,比较不同k的准确率(交叉验证)
- 写出构建kd树并搜索最近邻的算法代码
- 书本参考文献阅读
参考
《统计学习方法 第二版》
《深入浅出python机器学习》
K近邻法(KNN)原理小结 刘建平大佬的博客
Nearest Neighbor Pattern Classification
怎样理解 Curse of Dimensionality(维数灾难) 解释了为什么knn 有维度灾难