k近邻算法(k-Nearest Neighbor,kNN) 是一种简单的分类方法。给定一个训练数据集,对于一个新的数据样本,在训练数据集中搜索与该样本最邻近的$k$个样本,并将这$k$个样本的结果通过分类决策得到最终的输出结果。该算法需要注意的事项如下:

  • $k$值的选择:$k$值过小会使得模型的 近似误差(approximation error) 较小而 估计误差(estimation error) 较大,容易过拟合,这意味着模型复杂度较高;$k$值过大会使得模型的近似误差较大而估计误差较小,这意味着模型复杂度较低;通常通过交叉验证选择$k$值。
  • 距离度量:距离度量用于衡量样本点之间的距离,一般使用欧式距离,也可使用 其他距离度量
  • 分类决策规则: kNN 常使用 多数表决规则(majority voting rule) ,即邻域内出现最多的类别作为最终的输出类别。
  • kNN 可以看作是对数据空间的一种划分。对于数据空间中的每一个数据样本,距离该样本比其他所有样本更近的空间位置被划分到同一个区域中,该区域的类别由该样本点决定。

    kNN 算法没有显式的训练过程,而是在训练阶段把样本保存起来,待接受到测试样本后在进行处理。这类方法称为 懒惰学习(lazy learning) 以区别于通常的 急切学习(eager learning)

    kNN 算法实现简单,训练复杂度$O(1)$;但测试复杂度$O(N)$;其测试时间远大于训练时间,且距离评估指标容易受图像背景、颜色分布等影响,分类准确率较低。

    为了提高算法效率,在计算 kNN 中的样本距离时,引入矩阵计算(可以被 GPU 等硬件加速)。若$m$个特征维度为$d$的训练样本表示为矩阵$X \in \Bbb{R}^{m \times d}$;$n$个查询样本表示为矩阵$Y \in \Bbb{R}^{n \times d}$,样本间的 L2 距离表示为矩阵$L \in \Bbb{R}^{m \times n}$。则第$i$个训练样本和第$j$个查询样本之间的距离计算为:

    \[l_{ij} = \sqrt{\sum_{k=1}^{d} (x_{ik}-y_{jk})^2} = \sqrt{\sum_{k=1}^{d} (x_{ik}^2+y_{jk}^2-2x_{ik}y_{jk})} = \sqrt{\sum_{k=1}^{d} x_{ik}^2+ \sum_{k=1}^{d} y_{jk}^2-2 \sum_{k=1}^{d} x_{ik}y_{jk}}\]

    使用 numpy 将上述距离计算表示为矩阵运算:

    L = np.sqrt(
        np.sum(X.pow(2), axis=1).reshape(-1,1)+
        np.sum(Y.pow(2), axis=1).reshape(1,-1)-
        2*np.dot(X,Y.T)