K 近邻算法(K-Nearest Neighbor, KNN)属于一种简单且具有 “懒惰” 特性的监督式学习算法。其简单之处在于不进行参数估计,仅考量特征变量间的距离,以此解决分类或回归问题。“懒惰” 是因为该算法无显式学习及训练过程,仅在接到预测任务时才开始找寻近邻点,致使预测效率相对较低。同时,由于 K 近邻算法针对有响应变量的数据集,故而属于监督式学习方式。K 近邻算法既能用于解决分类问题,也可用于解决回归问题。
1 K近邻算法的基本原理
K 近邻算法的基本原理为:先凭借所有特征变量构建起一个特征空间,特征空间的维数即特征变量的个数。接着,针对某个测试样本 di,依据参数 K 在特征空间内寻觅与其最为邻近的 K 个训练样本观测值。最后,根据这 K 个训练样本的响应变量值或实际分类情况,得出测试样本 di 的响应变量拟合值或预测分类情况。
在处理分类问题时,遵循 “多数票规则” 确定,即若 K 个训练样本中包含样本数最多的类别是某一特定类别,那么测试样本 di 的分类就为此类别。而对于回归问题,则依据 K 近邻估计量确定,即将 K 个训练样本响应变量值的简单平均值作为测试样本 di 的响应变量拟合值。
由此可见,K 近邻算法较为简单且未使用参数,所以在不了解数据分布或者毫无先验知识的情况下,K 近邻算法不失为一个良好的选择。
在使用K近邻算法时,需要注意以下几点:
(1)所有的特征变量均需为连续变量。
这是因为K近邻算法中的核心概念是“近邻”,那么怎么来衡量“近邻”呢?这就需要定义“距离”,通常情况下是用欧氏距离。除了欧氏距离之外,还有以下几种距离量度可供使用:标准化欧氏距离;曼哈顿距离(Manhattan Distance);切比雪夫距离(Chebyshev Distance);闵可夫斯基距离(Minkowski Distance);带权重的闵可夫斯基距离(Minkowski Distance);马氏距离(Mahalanobis Distance)
(2)在进行K近邻算法之前,需要对特征变量进行标准化。
因为原始数据的量纲差距可能很大,如果不进行标准化,可能会因为量纲的问题引起距离测算的较大偏差,容易被那些取值范围大的变量所主导,可能会造成某个特征值对结果的影响过大,从而大大降低模型的效果。
(3)当K值较小时,K近邻算法对于“噪声”比较敏感。
因为K近邻算法在寻找K个近邻值时,并不依据响应变量的信息,只是通过特征变量在特征空间内寻找,所以即使一些特征变量对于响应变量的预测是毫无意义的(也就是所谓的“噪声”),也会被不加分别地考虑,从而在一定程度上形成了干扰,影响了预测效果。
(4)K近邻算法适用于样本全集容量较大且远大于特征变量数的情形。
因为对于高维数据来说,针对特定测试样本,可能很难找到K个训练样本近邻值,估计效率也会大大下降。
在Python中,K近邻算法针对分类问题的函数为KNeighborsClassifier(),而针对回归问题的函数KNeighborsRegressor()。
2 K值的选择
K 值代表在该算法中选取多少个近邻值用于构建模型。
存在两种较为极端的情形:其一,当 K 取值为 1 时,对于特定样本而言,仅选择与自身最近的那个近邻值。最近近邻值的响应变量值是多少或者属于何种类别,特定样本便相应地取值为多少或者归为何种类别,二者完全一致。其二,当 K 取值为整个样本容量时,对于每一个样本来说,都是将所有样本作为其近邻值,不再加以区分。
显而易见,这两种极端情况皆不可取。若 K 取值过小,整体模型会变得复杂。此时仅使用较小邻域中的训练样本进行预测,只有距离非常近的(相似的)样本才会发挥作用,这将导致模型的方差过大,容易出现过拟合现象,使得模型的泛化能力不足。例如,在 K 取值为 1 时,通过数学公式可以证明其泛化错误率上界为贝叶斯最优分类器错误率的两倍。而若 K 取值过大,整体模型则会变得简单。此时会使用过大邻域中的训练样本进行预测,距离非常远的(不太相似的)样本也会起作用,这将导致模型的偏差过大,容易出现欠拟合现象,导致模型没有充分利用最临近(相似)样本的信息。比如在 K 取值为整个样本容量时,K 近邻算法对每一个测试样本的预测结果将会变得一样(或者说每个测试样本在整个样本全集中的位置与地位都是相同的)。
所以,从 K 取值为 1 开始,随着取值的不断增大,K 近邻算法的预测效果会逐渐提升。然而,当达到一定数值(即最优数值)后,随着取值的进一步增大,K 近邻算法的预测效果就会逐渐下降。对于特定问题,我们需要找到最为合适的 K 值,使得 K 近邻算法能够达到最优效果。在 K 值的具体选择方面,要注意以下三点:一是在大多数情况下,K 值都比较小;二是为了避免产生相等占比的情况,K 值一般取奇数;三是为了更加精确地找到合适的 K 值,建议设置一个 K 值的取值区间,然后通过交叉验证等方法分别计算其预测效果,从而找到最好的 K 值。
3 K近邻算法的变种
1.设置K个近邻样本的权重前面我们介绍的K近邻算法
K个训练样本的地位是完全一样的,只要成为K个中的一个,不论这些训练样本与测试样本di之间的距离如何,都会被不加区别地对待。但是在很多情况下,用户可能会希望给予距离测试样本di更近的训练样本以更大的权重,这时候就可以在KNeighborsClassifier或KNeighborsRegressor函数中加入weights参数。
weights参数用于设置近邻样本的权重,可选择为"uniform","distance"或自定义权重。
● "uniform"为默认选项,即所有最近邻样本权重都一样。● "distance"意味着训练样本权重和特定测试样本di的距离成反比例,距离越近、权重越大。
如果样本是呈簇状分布的,即不同种类的样本在特征空间中聚类效果较好,那么采取"uniform"是不错的;如果样本分布比较乱,不同类别的样本相互交织在一起,那么使用"distance",即在预测类别或者做回归时,更近的近邻所占的影响因子更大,可能预测效果更优。除此之外,用户还可以自定义权重,进一步调优参数。
2.限定半径最近邻法
前面我们讲述的K近邻算法,针对某个测试样本di,是在特征空间内寻找与其最为近邻的K个训练样本观测值来完成计算,不论这些近邻值与特定测试样本di实际的距离如何,只考虑找到K个值。还有一种算法是限定半径最近邻法,它使用距离半径(radius)的方式,也就说针对某个测试样本di,在特征空间内寻找距离半径以内的训练样本,只要是在距离半径以内的训练样本,不论其个数有多少,都将作为近邻值来处理。在Python中,限定半径最近邻法分类函数和回归函数分别是RadiusNeighborsClassifier和RadiusNeighborsRegressor。
半径的设置通过参数radius来实现,参数默认值是1.0。在具体数值的选择方面,总体原则是应尽量保证每类训练样本与其他类别样本之间的距离足够远。所以半径的选择与样本分布紧密相关,用户可以通过交叉验证法来选择一个较小的半径。此外,在RadiusNeighborsClassifier和RadiusNeighborsRegressor中也可以加入weights参数,用于调节距离在半径以内的近邻样本的权重,其含义与K近邻算法相同。