k近邻法(k-nearest neighbor, kNN)

引言

k近邻法1968年由Cover和Hart提出。k近邻法不具有显式的学习过程,事实上,它是懒惰学习(lazy learning)的著名代表,此类学习技术在训练阶段仅仅是把样本保存起来,训练时间开销为零,待收到测试样本后再进行处理。

1. 原理

1、原理:是一种常用的监督学习方法,给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。也有无监督的最近邻,暂不讨论。
2、k近邻法的三要素
    距离度量、k值的选择及分类决策规则是k近邻法的三个基本要素。

  • 距离度量
      特征空间中的两个实例点的距离是两个实例点相似程度的反映。K近邻法的特征空间一般是n维实数向量空间 R n R^n Rn。使用的距离是欧氏距离,但也可以是其他距离,如更一般的Lp距离或Minkowski距离。
      设特征空间X是n维实数向量空间 R n R^n Rn x i , x j ∈ X , x i = ( x i ( 1 ) , x i ( 2 ) , … , x i ( n ) ) T , x j = ( x j ( 1 ) , x j ( 2 ) , … , x j ( n ) ) T , x i , x j 的 L p 距 离 定 义 为 x_i,x_j∈X,x_i=(x_i^{(1)},x_i^{(2)},…,x_i^{(n)})^T,x_j=(x_j^{(1)},x_j^{(2)},…,x_j^{(n)})^T,x_i,x_j的L_p距离定义为 xi,xjXxi=(xi(1),xi(2),,xi(n))T,xj=(xj(1),xj(2),,xj(n))T,xi,xjLp 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_{l=1}^{N}|x_i^{(l)}-x_j^{(l)}|^p)^{1/p} Lp(xi,xj)=(l=1Nxi(l)xj(l)p)1/p
    这里p≥1。
    当p=1时,称为曼哈顿距离(Euclidean distance),即 L 1 ( x i , x j ) = ∑ l = 1 N ∣ x i ( l ) − x j ( l ) ∣ L_1(x_i,x_j)=\sum_{l=1}^{N}|x_i^{(l)}-x_j^{(l)}| L1(xi,xj)=l=1Nxi(l)xj(l)
    当p=2时,称为欧氏距离(Euclidean distance),即 L 2 ( x i , x j ) = ( ∑ l = 1 N ∣ x i ( l ) − x j ( l ) ∣ 2 ) 1 / 2 L_2(x_i,x_j)=(\sum_{l=1}^{N}|x_i^{(l)}-x_j^{(l)}|^2)^{1/2} L2(xi,xj)=(l=1Nxi(l)xj(l)2)1/2
    当p=∞时,它是各个坐标距离的最大值,即 L ∞ ( x i , x j ) = m a x l ∣ x i ( l ) − x j ( l ) ∣ L_∞(x_i,x_j)=max_l|x_i^{(l)}-x_j^{(l)}| L(xi,xj)=maxlxi(l)xj(l)
  • k值的选择
      如果当K的取值过小时,一旦有噪声得成分存在们将会对预测产生比较大影响,例如取K值为1时,一旦最近的一个点是噪声,那么就会出现偏差,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
    如果K的值取的过大时,就相当于用较大邻域中的训练实例进行预测,学习的近似误差会增大。这时与输入目标点较远实例也会对预测起作用,使预测发生错误。K值的增大就意味着整体的模型变得简单;
      如果K==N的时候,那么就是取全部的实例,即为取实例中某分类下最多的点,就对预测没有什么实际的意义了;
      K的取值尽量要取奇数,以保证在计算结果最后会产生一个较多的类别,如果取偶数可能会产生相等的情况,不利于预测。
      常用的方法是从k=1开始,使用检验集估计分类器的误差率。重复该过程,每次K增值1,允许增加一个近邻。选取产生最小误差率的K。
      一般k的取值不超过20,上限是n的开方,随着数据集的增大,K的值也要增大。
  • 分类决策规则
    (1)在分类任务中的可使用“投票法”,即选择这k个样本中出现最多的类别标记作为预测结果;
    (2)在回归任务中可使用“平均法”,即将这k个样本的标记平均值作为预测结果。
    (3)还可以根据距离远近,对样本进行加权,实现加权平均或加权投票。

2. 程序实现

2.1 Python3实现

实现步骤:

    1.计算已知类别数据集中每个点与该点之间的距离
    2.按照距离递增顺序排序
    3.选取与该点距离最近的k个点
    4.确定前k个点所在类别出现的频率
    5.返回前k个点出现频率最高的类别作为该点的预测分类
# knn算法实现
import numpy as np
def knn(data, dataSet, labels, k):
    # 计算两个向量之间的欧式距离
    def calDist(X1, X2):
        sum = 0
        for x1, x2 in zip(X1, X2):
            sum += (x1 - x2) ** 2
        return sum ** 0.5
    n = np.shape(dataSet)[0]
    for i in range(n):
        dist = calDist(data, dataSet[i])
        # 只记录两点之间的距离和已知点的类别
        labels[i].append(dist)
        # 按照距离递增排序
        labels.sort(key = lambda x:x[1])
        count = {}
        # 统计每个类别出现的频率
        for i in range(k):
            key = labels[i][0]
            if count.has_key(key):
                count[key] += 1
            else:
                count[key] = 1
        # 按频率递减排序
        sortCount = sorted(count.items(),key = lambda item: item[1], reverse = True)
        return sortedCount[0][0] # 返回频率最高的key, 即label       
2.2 Python3中sklearn-KNN的代码实现
KNeighborsClassifier( n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, n_jobs=1, **kwargs )
  • sklearn中的KNN包,有几个可调参数,及每个参数代表的意义
  • n_neighbors,即选择k值,较大的k值可以容忍较多的噪声,但是会使得分类的结果变的不那么精确;但样本不平衡时,一个类样本容量很大,其他样本容量很小,导致输入新样本时,该样本邻近中大样本占多数,因此可以采取权值的方法(和样本距离小的邻近权值大)来改进,减少k值选择对结果的影响;可以通过循环来尝试不同的k值的效果。
  • weights,即权重设置,‘uniform’和‘distance’,对每个点赋予同样的权重,或者根据距离远近,赋予不同的权重(距离越远权重越小)。
  • algorithm,即搜索最近邻算法的选择,包括ball_tree、kd_tree、brute和auto。
  • brute代表Brute Force算法,就是一个最原始(蛮力)邻居搜索做法,Brute Force在寻找邻居时,会把输入的点同所有样本中的点做一个距离计算,然后再排序选择最近的点。
    kd_tree代表KD树算法,为了解决BF算法效率低下的问题,人们提出了很多树形结构的算法,树形结构的主要贡献在于,它们一般通过事先的合理组织,降低了我们搜索中的开销,也就是使用树形结构的算法,我们在搜索时可以不用每个样本都去计算距离了,这无疑降低了很多的开销。在不太高的维度(小于20)下,KD树的效果是很不错的,不过当维度走向更高时,KD树的效率也会随之下降,这也呼应了我们之前提到的“维度之殇”的问题。
    ball_tree代表Ball Tree算法,KD-Tree是为了解决Brute Force的效率问题,那么Ball-Tree也就是为了解决KD-Tree在高维情况下的效率不佳的另一个做法了,Ball树在构建的时候,比起KD树要复杂许多,不过在最后的搜索过程中,其表现就会非常好。
    三者的选取:样本≤30,用BF;样本较大,但维度≤20,用KD_tree;维度更多的,用ball tree。

引用:https://www.jianshu.com/p/eb2d0659187a

3. 优缺点

优点:
1.简单,易于理解,易于实现,无需估计参数,无需训练;
2. 适合对稀有事件进行分类;
3.特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好。
缺点
1.数量并不能影响运行结果,即当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。 该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。
2.计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。
3.可理解性差,无法给出像决策树那样的规则。`

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值