k近邻算法笔记

k近邻法(K-neareset neighbor, KNN)是一种基本分类与回归的算法,对给定的训练实例点和输入实例点,首先确定输入实例点的k个最近邻训练实例点,然后利用这k个训练实例点的类的多数来预测输入实例点的类(少数服从多数的思想)。

一个形象的例子可见一文搞懂k近邻(k-NN)算法(一)

1. k近邻算法

输入:训练数据集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) ,   , ( x N , y N ) } T=\{(x_{1},y_{1}),(x_{2},y_{2}),\cdots,(x_{N},y_{N})\}
输出:实例 x x 所属的类 y y

  1. 根据给定的距离度量,在训练集 T T 中找出与 x x 最邻近的 k k 个点,涵盖这 k k 个点的 x x 的邻域记作 N k ( x ) N_{k}(x)
  2. N k ( x ) N_{k}(x) 中根据分类决策规则(如多数表决)决定 x x 的类别 y y
    y = a r g max c j x i N k ( x ) I ( y i = c j ) , i = 1 , 2 ,   , N ; j = 1 , 2 ,   , K y = arg \max\limits_{c_{j} }\sum\limits_{x_{i}\in N_{k}(x)} I (y_{i} = c_{j}), i=1,2,\cdots,N; j = 1,2,\cdots, K
    I I 为指示函数,即当 y j = c j y_{j} = c_{j} I I 为1,否则 I I 为0。

k = 1 k=1 时,称为最近邻算法。

2. k近邻模型三要素

2.1 距离度量

特征空间中两个实例点的距离是两个实例点相似程度的反映,k近邻模型一般使用的距离是欧式距离,即 L 2 L_{2}

  • 一般的 L p L_{p} 距离( p > = 1 p>=1 ):设特征空间 X X n n 维实数向量空间 R n R^n x i , x j X x_{i},x_{j}\in X , x i = ( x i ( 1 ) , x i ( 2 ) ,   , x i ( n ) ) T x_{i} = (x_{i}^{(1)},x_{i}^{(2)},\cdots,x_{i}^{(n)})^T x j = ( x j ( 1 ) , x j ( 2 ) ,   , x j ( n ) ) T x_{j} = (x_{j}^{(1)},x_{j}^{(2)},\cdots,x_{j}^{(n)})^T x i , x j x_{i},x_{j} L p L_{p} 距离定义为
    L p ( x i , x j ) = ( l = 1 n x i ( l ) x j ( l ) ) p ) 1 p L_{p}(x_{i},x_{j}) = (\sum\limits_{l=1}^n|x_{i}^{(l)} - x_{j}^{(l)})|^p)^{\frac{1}{p}}
  • 曼哈顿距离: p = 1 p=1
  • 欧式距离: p = 2 p=2

2.2 k值

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

  • k值小时,相当于用较小的邻域中的训练实例进行预测,k近邻模型更复杂,容易发生过拟合,因为很容易学习到一些噪声而忽略了数据真实的分布;
  • k值大时,相当于用较大邻域中的训练实例进行预测,k近邻模型更简单,如果k值太大则完全忽略训练实例汇总的大量有用的信息;
  • 在应用中k值一般取一个比较小的数值,通常由交叉验证选择最优的k值。

2.3 分类决策规则

多数表决:由输入实例的 k k 个邻近的训练实例中的多数类决定输入实例的类。

用误分类的概率判断模型好坏,误分类率最低最好,误分类率:
1 k x i N k ( x ) I ( y i c j ) = 1 1 k x i N k ( x ) I ( y i = c j ) \frac{1}{k}\sum\limits_{x_{i}\in N_{k}(x)}I(y_{i} \ne c_{j}) = 1 - \frac{1}{k}\sum\limits_{x_{i} \in N_{k}(x)}I(y_{i} = c_{j})
要使误分类率最小即经验风险最小,就要使 x i N k ( x ) I ( y i = c j ) \sum\limits_{x_{i} \in N_{k}(x)}I(y_{i} = c_{j}) 最大,所以多数表决规则等价于经验风险最小化。

3. kd树

kd树是二叉树,表示对 k k 维空间的一个划分。构造kd树相当于不断地用垂直于坐标轴的超平面将 k k 维空间切分,构成一系列的 k k 维超矩形区域。

3.1 构造kd树

输入: k k 维空间数据集
输出:kd树

  1. 选择以 x ( l ) x^{(l)} 为坐标轴,以所有实例的 x ( l ) x^{(l)} 坐标的中位数为切分点,将通过切分点并与坐标轴 x ( l ) x^{(l)} 垂直的超平面为切分平面,将根结点对应的超矩形区域切分为两个子区域,由此生成左右两个子结点;
  2. 对于子区域,继续选取 x ( l ) x^{(l)} 为切分坐标轴, l ( l + 1 ) m o d ( k ) l \gets (l+1) mod(k) ,将子区域继续切分(这里轮流沿着每一个维度进行分割, m o d ( k ) mod(k) 是因为一共有 k k 个维度,在沿着最后一个维度切割之后再重新回到第一个维度);
  3. 直到切分后的子区域没有实例点存在时停止,从而形成kd树的区域划分(终止时的结点为叶结点)。

3.2 搜索kd树

输入:已构造的kd树;目标点 x x
输出: x x 的最近邻

  1. 在kd树中找出包含目标点 x x 的叶结点:从根结点出发,递归地向下访问kd树。目标点 x x 当前维的坐标小于切分点的坐标,移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止。
  2. 以此叶结点为“当前最近点”。
  3. 递归地向上回退,在每个结点进行以下操作:
    (a) 如果该结点保存的实例点比当前最近点距离目标点更近,则以该实例点为“当前最近点”;
    (b) 当前最近点一定存在于该结点一个子结点对应的区域。检查该子结点的父结点的另一子结点对应的区域是否有更近的点。即检查另一子结点对应的区域是否与以目标点为球心,以目标点与“当前最近点”间的距离为半径的超球体相交。若相交,则在对应区域存在距离目标更近的点,移动到另一子结点继续递归搜索;否则向上回退。
  4. 回退到根结点时,搜索结束,最后的“当前最近点”即为 x x 的最近邻点。

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

3.3 例子

【量化课堂】kd 树算法之详细篇,这个例子可以帮助理解构造kd树和搜索kd树的算法过程。

4. KNN优缺点

4.1 优点

  • 理论成熟,思想简单,既可用来做分类也可做回归
  • 可用于非线性分类
  • 训练时间复杂度比支持向量机之类的算法低,仅为 O ( n ) O(n)
  • 和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感
  • 由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分类样本集来说,KNN方法较其他方法更为合适
  • 比较适用于样本容量比较大的类域的自动分类

4.2 缺点

  • 计算量大,尤其是特征数非常多时
  • 样本不平衡时,对稀有类别的预测准确率低
  • KD树、球树之类的模型建立需要大量的内存
  • 使用懒散学习方法,基本上不学习,导致预测时速度比起逻辑回归之类的算法慢
  • 相对决策树模型,KNN模型可解释性不强

5. sklearn应用

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, n_jobs=1, **kwargs)[source]

具体见sklearn文档:sklearn.neighbors.KNeighborsClassifier

# 使用KNN分类需要对数据进行归一化,因为要计算距离
from sklearn.preprocessing import MinMaxScaler
mm = MinMaxScaler()
mm.fit(X_train)
X_train_mm = sc.transform(X_train)
X_test_mm = sc.transform(X_test)

# KNN 
from sklearn.neighbors import KNeighborsClassifier 
# n_neigbors:k   
# metric&p:距离度量,默认为欧式距离(minkowski&2)
knn = KNeighborsClassifier(n_neighbors=5, p=2, metric='minkowski')
knn.fit(X_train_mm, y_train)

详细代码见github

6. reference

本文同步发布在我的github.io

猜你喜欢

转载自blog.csdn.net/weixin_43004311/article/details/82194170
今日推荐