k-Nearest Neighbor.

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

  1. $k$值的选择:$k$值过小会使得模型的近似误差(approximation error)较小而估计误差(estimation error)较大,容易过拟合,这意味着模型复杂度较高;$k$值过大会使得模型的近似误差较大而估计误差较小,这意味着模型复杂度较低;通常通过交叉验证选择$k$值。
  2. 距离度量:距离度量用于衡量样本点之间的距离,一般使用欧式距离,也可使用其他距离度量
  3. 分类决策规则: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)
)