K-NN(k-nearset neighbor)算法原理及其还没有实现(python原始代码实现和sk_learn实现)

机器学习有三宝:
一、模型
二、策略
三、算法

模型:
先来一波简介:
K-NN是一种基本分类和回归方法,这篇博客我们只讨论分类问题中的k近邻法,kNN的输入为实例的特征向量,对应于特征空间的点;输出为实例的分类类别。
假设给定一个训练数据集,其中类别已定。分类时,给定测试点,选定k个离测试点最近的点,得到k个结果,对结果进行投票,选择票数最高的结果作为分类结果。
因此,k近邻法不像感知机一般,具有显式的学习过程,它只是利用训练数据集对特征空间进行划分
空间划分
其实,KNN的原理很简单,可以理解为近朱者赤近墨者黑。
KNN的三个基本要素:k值的选定,距离度量,分类决策规则
准备:训练集T={(x1,y1),(x2,y2),(x3,y3),…,(xn,yn)}
其中,xi∈X∈Rn,为实例的特征向量,yi∈Y={c1,c2,c3,…,cn}为分类类别
输出为实例x所属的类y
接下里便是上文所提到的投票机制了

k近邻的特殊情况是k=1时,成为最近邻算法,对于输入实例x的最近邻的点作为输入实例的类别

距离度量:
常见的距离度量有欧式距离,但也可以是更常见的Lp距离,Minkowski 距离
这次,我们聊聊Lp距离:
设特征空间X是n维实数的向量空间Rn,xi,xj∈X,xi =(xi1,xi2,xi3,…xin)T,
xj =(xj1,xj2,xj3,…xjn)T,则xi,xj的Lp距离定义为
Lp距离定义(p>=1)

当p=2时,就是我们常说的欧式距离
当p=1时,就是曼哈顿距离
当p=无穷大时,就是各个座标距离的最大值,即
在这里插入图片描述
为什么P取无穷时,会是这个结果?
这个我用python代码证明:
通过绘制散点图可以看到, 当p=无穷时,是一个直线,当p = 2时,会是一个圆
p=10w
p=2
python代码证明走起:

import matplotlib.pyplot as plt
import numpy as np
def Sum(p,xi,xj):#xj始终为0,0,0....
    sum = 0
    if(len(xi)!=len(xj)):
        print("their len has to be same!")
    else:
        temp_sum = 0
        for i in range(len(xi)):
            temp_sum += (xi[i]-xj[i])**p
        sum = pow(temp_sum,1/p)
        return sum
if __name__=="__main__":
    yi = [0,0]
    i = 0.01
    zi = []
    xi = [i,0]
    while i < 1.01:
        temp = 0
        while abs(Sum(2,xi,yi)-1)>0.08: #设定阈值,这个浮点数0.08的设置关系到散点图能不能很好的模拟图像
            temp = temp + 0.01
            xi = [i,temp]
        print(Sum(2,xi,yi))
        print(xi)
        zi.append(xi[1])
        i += 0.01
        xi=[i,temp]
        print(i)
    Xj = np.arange(0,1,0.01)
    Xi = zi
    fig = plt.figure()
    ax1 = fig.add_subplot(111)
    ax1.set_title('Lp')
    # 设置X轴标签
    plt.xlabel('Xj')
    # 设置Y轴标签
    plt.ylabel('Xi')
    # 画散点图
    ax1.scatter(Xj, Xi, c='r', marker='o')
    plt.show()

假定|xi|=2,xj=[0,0],距离为1
则绘图如下:
在这里插入图片描述
上面的代码只有第一象限的结果,关于p=无穷时,代码里实现的也是基于xi1的图像,同理,当我们基于xi2进行绘图时,将产生一条垂直于x轴的直线。
关于k值的选择,这里再提一下:这篇博客只考虑k=1时的情况。但是我们实际应用的时候,可能还要考虑取其他k值,k值一般取一个比较小的数值,通常采用交叉验证来选取最优的k值

分类决策规则:
kNN往往是是多数表决,即由输入实例的k个邻近的训练例子中的多数类决定输入实例的类,多数表决等价于经验风险最小化
证明如下:P(Y ≠ f(x))= 1 - P(Y = f(x)),则误分类率:(I是指示函数,当yi=cj时,取值为1,否则为0)
误分类率
要使误分类率最小,等价于要在这里插入图片描述
最大,所以多数表决等价于经验风险最小化
实现:
构建kd树,搜索kd树
开始种树 忄忄忄忄忄:
kd 树是二叉树,表示对k维空间的划分,构建kd树相当于不断地用垂直座标轴的超平面将k维空间进行划分,构成一系列的k维超矩形区域,kd树的每一个结点对应于一个k维超矩形区域。
算法:
在这里插入图片描述
在这里插入图片描述
捡个栗子来看看:
T ={(2,3)T,(5,4)T,(9,6)T,(4,7)T,(8,1)T,(7,2)T} (后面的T表示转置矩阵)
构建第一步: 以xi1作为判断标准:
排序后,取(5,4)T, (7,2)T, 按照上面算法来说,应该取5和7的中位数,但是我们还是取偏大的(7,2)作为根节点,小于xi1小于7的做左节点,反之,则作右节点
后面根据 L= J(mod k)+1决定比较的顺序。
以此类推,便很快构建出kd树
在这里插入图片描述
知道你们懒得推,我把图放出来了

接下来,我们开始kd树的最近邻搜索

  1. 测试点首先从根节点出发,按照不同深度不同的xi比较标准,决定往左还是往右,最后到达叶节点
  2. 以当前叶节点作为最近邻点,递归的往上推,对每一个节点做以下操作
    (a)查看父节点,分别比较父节点、当前最近邻节点 与 测试点的距离,如果前者较小,则最近邻节点更新为该父节点。
    (b)当前最近邻节点一定存在于该父节点的一个子节点的区域,检查该父节点的另一个子节点,看是否有更近的节点,如果有,就更新当前最近邻点,如果没有,则接着向上递归
    如何判断是否可能有最近邻节点呢?
    原理很简单:
    以测试点作为超球体的球心,以“当前最近邻节点”到球心的距离作为半径,若这个若另一个子节点的区域与超球体相交,则可能有“最近邻节点”,否则觉悟可能
  3. 当回归到根节点时,停止搜索,最后的当前“最近邻节点”为最近节点。
    还是捡个栗子:
    在这里插入图片描述
    搜索路径:S->D->B->F->A->C->E
    代码后续补上:
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章