zoukankan      html  css  js  c++  java
  • 机器学*——K*邻算法(KNN)

    1 前言  

      Kjin邻法(k-nearest neighbors,KNN)是一种基本的机器学*方法,采用类似“物以类聚,人以群分”的思想。比如,判断一个人的人品,只需观察他来往最密切的几个人的人品好坏就可以得出。这里就运用了KNN的思想。KNN方法可以做分类,也可以做回归,这点和决策树算法相同。

      KNN做回归和分类的主要区别在于做预测时候的决策方式不同。

      KNN做分类预测时,一般是选择多数表决法,即训练集里和预测的样本特征最jin的K个样本,预测为里面有最多类别数的类别。
      KNN做回归时,一般是选择平均法,即最jin的K个样本的样本输出的平均值作为回归预测值。

    2 KNN算法原理  

      给定一个训练集,对新输入的实例,在训练集中找到与该实例最邻jin的k个实例,这k个实例的多数属于某个类,我们就把该输入实例分为这个类。

    2.1 算法描述

      输入:训练数据集$T={(x_1,y_1),(x_2,y_2),...,(x_N,y_N)}$,其中$x_iin{chi}$为实例的特征向量,$y_iin{{c_1,c_2,...,c_m}}$为实例的类别,实例特征向量x。
      输出:实例 x 所属的类别 y。
      1.根据给定的距离度量方式,在训练集T中找到与x最邻jin的k个点,涵盖着k个点的x的领域记住$N_k(x)$。
      2.在$N_k(x)$中根据分类决策规则决定x的类别y
        $y=argmax_{c_j}sum_{x_iin{N_k(x)}}I(y_i=c_j)$
      其中$I(y_i=c_j)$为指示函数,当$y_i=c_j$的时候$I=1$,后者$I=0$ 。

    3. KNN的基本要素

      对于一个确定的训练集,确定距离度量、k值和分类决策规则,就能对任何一个新的实例,确定它的分类。

    3.1 距离度量

      距离度量是描述特征空间中两个实例的距离,也是这两个实例的相似程度。在n维实数向量空间中,我们主要使用的距离度量方式是欧式距离,但也可以使用更加一般化$L_p$距离(闵可夫斯基距离)。
      在特征空间中,取出两个特征$x_i$,$x_j$,它们分别是n维的特征向量。
      Lp距离(闵可夫斯基距离)
        $L_p(x_i,x_j)=(sum_{l=1}^n|x_i^l-x_j^l|^p)^{frac{1}{p}}$
      欧氏距离
        $L_2(x_i,x_j)=(sum_{l=1}^n|x_i^l-x_j^l|^2)^{frac{1}{2}}$
      曼哈顿距离
        $L_1(x_i,x_j)=sum_{l=1}^n|x_i^l-x_j^l|$
      $L_{infty}$距离
        $L_{infty}(x_i-x_j)=max_{l}|x_i^l-x_j^l|$

    3.2 k值的选择

      对于k值的选择,没有一个固定的经验,一般根据样本的分布,选择一个较小的值,然后通过交叉验证选择一个合适的k值。
      • 如果选择较小的K值
        • “学*”的jin似误差(aproximation eror)会减小,但 “学*”的估计误差(estimation eror) 会增大。
        • 噪声敏感。
        • K值的减小就意味着整体模型变得复杂,容易发生过 拟合。
      • 如果选择较大的K值,
        •减少学*的估计误差,但缺点是学*的jin似误差增大。
        •K值的增大 就意味着整体的模型变得简单。
      一个极端是k等于样本数m,则完全没有分类,此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单。

    3.3 分类决策规则

      对于分类决策规则,一般都是使用前面提到的多数表决法。

    4. kd树  

      KNN算法最简单的实现方式:计算输入实例和所有训练实例的距离,进行排序,取前k个,进行分类。当训练集特别大的时候,非常耗时。
      下面介绍kd树的方式,kd树通过减少输入实例和训练实例的计算次数来达到优化的目的。
      kd树是一种对K维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。
      kd树是二叉树,表示对K维空间的一个划分。构造Kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一 系列的k维超矩形区域。Kd树的每个结点对应于一个k维超矩形区域.
      kd树算法包括三步,第一步是建树,第二步是搜索最jin邻,最后一步是预测。

      

    4.2 kd树搜索最jin邻居

      当我们生成kd树以后,就可以去预测测试集里面的样本目标点了。预测的过程如下:
      1、对于一个目标点,我们首先在kd树里面找到包含目标点的叶子节点。以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最jin邻的点一定在这个超球体内部。
      2、然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体是否和超球体相交,如果相交就到这个子节点寻找是否有更加jin的jin邻,有的话就更新最jin邻,并且更新超球体。如果不相交那就简单了,我们直接返回父节点的父节点,在另一个子树继续搜索最jin邻。
      3、当回溯到根节点时,算法结束,此时保存的最jin邻节点就是最终的最jin邻。
      从上面的描述可以看出,kd树划分后可以大大减少无效的最jin邻搜索,很多样本点由于所在的超矩形体和超球体不相交,根本不需要计算距离。大大节省了计算时间。
      搜索过程,大致如下:

    4.3 kd树预测

      有了kd树搜索最jin邻的办法,kd树的预测就很简单了,在kd树搜索最jin邻的基础上,我们选择到了第一个最jin邻样本,就把它置为已选。在第二轮中,我们忽略置为已选的样本,重新选择最jin邻,这样跑k次,就得到了目标的k个最jin邻。然后根据多数表决法,如果是KNN分类,预测为k个最jin邻里面有最多类别数的类别。如果是KNN回归,用k个最jin邻样本输出的平均值作为回归预测值。

    4.4 示例:使用k-jin邻算法进行分类

    from sklearn.datasets import make_blobs
    # 生成数据
    """
    代码中,生成60个训练样本,这60个样本分布在以centers参数指定中心点周围。cluster_std是标准差,用来指明生成的点分布的松散程度。
    生成的训练数据集放在变量X里面,数据集的类别标记放在y里面。
    make_blobs函数是为聚类产生数据集
    产生一个数据集和相应的标签
    n_samples:表示数据样本点个数,默认值100
    n_features:表示数据的维度,默认值是2
    centers:产生数据的中心点,默认值3
    cluster_std:数据集的标准差,浮点数或者浮点数序列,默认值1.0
    center_box:中心确定之后的数据边界,默认值(-10.0, 10.0)
    shuffle :洗乱,默认值是True
    random_state:官网解释是随机生成器的种子
    """
    centers = [[-2,2], [2,2], [0,4]]
    X, y = make_blobs(n_samples=100,centers=centers,random_state=6, cluster_std=0.60)
    print(X)  #坐标点
    print(y)  #类别
    # 画出数据
    """
    这些点的分布情况在坐标轴上一目了然,其中三角形的点即各个类别的中心节点。
    """
    import matplotlib.pyplot as plt
    import numpy as np
    plt.figure(figsize=(16,10), dpi=144)
    c = np.array(centers)
    # 画出样本
    plt.scatter(X[:,0], X[:,1], c=y, s=100, cmap='cool')
    # 画出中心点
    plt.scatter(c[:,0], c[:,1], s=100, marker='^',c='orange')
    plt.savefig('knn_centers.png')
    plt.show()
    
    # 使用KNeighborsClassifier对算法进行训练,我们选择参数k=5
    from sklearn.neighbors import KNeighborsClassifier
    # 模型训练
    k = 5
    clf = KNeighborsClassifier(n_neighbors = k)
    clf.fit(X, y)
    # 对一个新样本进行预测:
    # 进行预测
    """
    我们要预测的样本是[0, 2],使用kneighbors()方法,把这个样本周围距离最*的5个点取出来。
    取出来的点是训练样本X里的索引,从0开始计算。
    """
    X_sample = np.array([[0, 2]])
    y_sample = clf.predict(X_sample)
    neighbors = clf.kneighbors(X_sample, return_distance=False)
    
    # 把待预测的样本以及和其最*的5个样本在图上标记出来。
    # 画出示意图
    plt.figure(figsize=(16,10), dpi=144)
    c = np.array(centers)
    plt.scatter(X[:,0], X[:,1], c=y, s=100, cmap='cool') # 出样本
    plt.scatter(c[:,0], c[:,1], s=100, marker='^',c='k') # 中心点
    plt.scatter(X_sample[0][0], X_sample[0][1], marker="x",
               s=100, cmap='cool')      # 待预测的点
    for i in neighbors[0]:
        plt.plot([X[i][0], X_sample[0][0]], [X[i][1], X_sample[0][1]],
                'k--', linewidth=0.6)  # 预测点与距离最*的5个样本的连线
    plt.savefig('knn_predict.png')
    plt.show()
    View Code

    因上求缘,果上努力~~~~ 作者:每天卷学习,转载请注明原文链接:https://www.cnblogs.com/BlairGrowing/p/14840623.html

  • 相关阅读:
    aptana中删除空行
    css预处理的引入与问题
    rsyslog 服务器重启后 发现不能接受到外部日志 只能接受本地日志 关闭防火墙即可
    php访问其他网站接口
    mysql 表查询结果 总行数计算
    linux centos 恢复 还原 备份 Snapper 快照说明
    linux 服务 启动 关闭 列表
    linux yum 安装 卸载
    php7 mysql_pconnect() 缺失 解决方法
    搭建一个免费的,无限流量的Blog----github Pages和Jekyll入门
  • 原文地址:https://www.cnblogs.com/BlairGrowing/p/14840623.html
Copyright © 2011-2022 走看看