机器学习-KNN-2020-7

KNN(k-nearest neighbor)k近邻

用途:回归 or 分类

KNN分类预测时,一般是选择多数表决法,即训练集里和预测的样本特征最近的K个样本,预测为里面有最多类别数的类别。

KNN做回归时,一般是选择平均法,即最近的K个样本的样本输出的平均值作为回归预测值。

分类:

原理: 当预测一个新的输入实例x类别,根据它最近k个点是什么类别来判断x属于什么类别(k个点多数属于的那个类,就是预测x的类 多数表决)

算法 :

输入:训练数据集  T = {  } ,其中是特征向量,是标签 ,类别为{C1,C2,..Ck},和待预测x类别  

输出:x 的类别 

  1. 根据给定的距离度量,在训练集T中找出与x最近的k个点,涵盖这个k个点的邻域记:

  2.  在中根据分类决策规则(多数表决)决定x的类别 y                 

    y =  arg () , i =1,2,...n;j=1,2,...k

特点:

1:非参的,不具有显示的学习过程,懒惰算法,利用训练数据对特征向量空间进行划分,做为分类模型,建立的模型结构是根据数据来决定的,不需要训练

2:简单易用

3: 对内存要求较高,因为该算法存储了所有训练数据, 预测阶段可能很慢

3个基本要素:

  1. k值得选择(交叉验证)

    一般通过交叉验证选择一个合适的k值,

    选择较小的k值,泛化误差会增大,容易发生过拟合。

    选择较大的k值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少泛化误差,但缺点是训练误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单。

  2. 距离的度量 

    大多数情况是:欧式距离,曼哈顿距离,切比雪夫距离,闵可夫斯基距离

  3. 分类决策规则 (多数表决)

KNN代码的实现步骤:

  1.  计算已知类别数据集中的点与当前点之间的距离;

  2.  按照距离递增次序排序;

  3.  选取与当前点距离最小的k个点;

  4. 确定前k个点所在类别的出现次数;

  5. 返回前k个点出现次数最多的类别作为当前点的预测分类。

 

算法示例:

鸢尾花数据集:

代码实现KNN算法:

import numpy as npimport operatorfrom sklearn import datasetsimport randomimport tensorflow as tfimport  matplotlib.pyplot as pltdef KNN_classfy(x,data,label,k=1):    """    x: 预测分类数据    data: 训练数据    label: 训练数据的标签    k:  k值    return : x的分类    """    shape_row = data.shape[0] # 训练数据的行数    xMat = np.tile(x,(shape_row,1)) #将x扩展成与训练数据大小相同的矩阵,按行扩展    distance =( ((xMat - data)**2).sum(axis=1))**0.5 #求出x到每个训练点的距离    sortDistance = distance.argsort() #将所有距离排序,返回的是数组的索引    classCount ={} #创建一个字典    for i in range(k):        label_near =label[sortDistance[i]] # 找到最近第i个数据的标签         #统计每个类中数据的个数        classCount[label_near] =classCount.get(label_near,0)+1 #在字典中,对应标签值+1,默认label_near下标从0开始    #将每一类按个数排序,降序    sortClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)    return sortClassCount[0][0] #返回类别# 加载数据iris = datasets.load_iris()data = iris.datalabel = iris.target#打乱数据index = [i for i in range(len(data))] random.shuffle(index)data = data[index]label = label[index]  y_predict = []k=10 #参数设置#预测数据for i in data:    y_predict.append(KNN_classfy(i,data,label,k))#获得准确率predciton_result= tf.equal(y_predict,label)accuracy = tf.reduce_mean(tf.cast(predciton_result,tf.float32))print("准缺率:",end="")print(accuracy.numpy())#画图col = ['HotPink', 'red', 'Chartreuse', 'yellow', 'LightSalmon']for i in range(len(data)):    plt.scatter(data[i][0],data[i][1],linewidth=5, color=col[y_predict[i]])plt.xlabel('sepal length')plt.ylabel('sepal width')plt.title("KNN    k = %d"%(k))plt.show()y

运行结果:(没怎么处理最原始的,准确率就这么高啊!!)

KDTree:

当训练数据很大的时候,计算到每个点的距离,然后选出类别最多这种算法非常耗时,为了提高搜索效率,引入kd树

kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是是一种平衡二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索, 从而减少搜索的计算量。

两个步骤:

  1. 首先要构造平衡kd树

  2. 然后搜索kd树(首先找到包含目标结点的叶结点,然后从叶结点出发,依次退回到父结点,不断查找与目标结点最近的结点)

具体算法参照<<统计学习方法>> p54,p56

例子:给一个二维空间的数据集

T ={}

构造一棵平衡kd树

代码:

#结点class Node(object):    def __init__(self,x,split,left,right):        self.x = x # 一个样本点        self.split = split #划分的序号        self.left = left  #左子树        self.right =right #右子树#生成一颗kd树    class KDTree(object):    def __init__(self,data): # data是整个数据集        k =len(data[0])  #数据的维度         #递归创建二叉树        def createNode(split,data):            if not data:   #数据集为空                return None              data.sort(key=lambda x:x[split])#将数据排序x: x[split]就是将数据按照第split维度排序            split_pos = len(data) //2 #整数            mid = data[split_pos]  #找到中间的点            split_next = (split+1) %k #深度+1            #递归创建kd树            return Node(mid,split,createNode(split_next,data[:split_pos]),                       createNode(split_next,data[split_pos+1:]))        self.root = createNode(0, data)  #从第0维分量开始构建kd树,返回根节点# KDTree的前序遍历def preOrder(root):      print(root.x)   #遍历根结点    if root.left:      # 节点不为空,递归左结点        preOrder(root.left)       if root.right:          preOrder(root.right)  data = [[2,3],[5,4],[9,6],[4,7],[8,1],[7,2]] #数据kd = KDTree(data)  #创建kd树preOrder(kd.root) #前序遍历输出

运行结果:

sklearn 在鸢尾花数据集 实现KNN算法:

1:决定K的值是多少,要选出最优的K值,使用sklearn中的交叉验证方法

代码实现:

import sklearn.datasets from sklearn.model_selection import cross_val_scoreimport matplotlib.pyplot as pltimport numpy as npfrom sklearn.neighbors import KNeighborsClassifier# 加载数据iris = datasets.load_iris()data = iris.datalabel = iris.target#选取一个合适的kk_range = range(1,31)k_error = [] #错误率for k in k_range:    #构造一个为k 的分类器    knn = KNeighborsClassifier(n_neighbors=k)     #交叉验证    scores = cross_val_score(knn,data,label,cv=6,scoring='accuracy')    k_error.append(1-scores.mean())#画图,x轴为k值,y值为误差值plt.plot(k_range, k_error)plt.xlabel('K')plt.ylabel('Error')plt.show()

运行结果:(图中可以看出k=11错误率最低)

2:KNN算法,比较了weights(权重)'uniform' ,distance(越近越重要):

from sklearn.model_selection import cross_val_scoreimport matplotlib.pyplot as pltimport numpy as npfrom matplotlib.colors import ListedColormapfrom sklearn import neighbors from sklearn import datasets # 加载鸢尾花数据集iris = datasets.load_iris()data = iris.data[:,:2]label = iris.targetk= 11h = .02  # 网格中的步长# 创建彩色的图color_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])color_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])#weights是KNN模型中的一个参数,绘制两种权重参数下KNN的效果图for weights in ['uniform', 'distance']:    #创建一个knn分类器    clf = neighbors.KNeighborsClassifier(k, weights=weights)    clf.fit(data, label)    # 绘制决策边界。为此,我们将为每个分配一个颜色    x_min, x_max = data[:, 0].min() - 1, data[:, 0].max() + 1    y_min, y_max = data[:, 1].min() - 1, data[:, 1].max() + 1    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),                         np.arange(y_min, y_max, h))    # xx.ravel() 是将数据转成1 维 , np_c[xx,yy] 将数据左右连接    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])#预测    # 将结果放入一个彩色图中    Z = Z.reshape(xx.shape)    plt.figure()    plt.pcolormesh(xx, yy, Z, cmap=color_light)    # 绘制训练点    plt.scatter(data[:, 0], data[:, 1], c=label, cmap=color_bold)    plt.xlim(xx.min(), xx.max())    plt.ylim(yy.min(), yy.max())    plt.title("KNN classification (k = %i, weights = '%s')" %(k, weights))    plt.show()

运行结果:(distance更加光滑一些)

KNN和Kmeans

相同:

  1. K值都是重点

  2. 都需要计算平面中点的距离

相异:
KNN和Kmeans的核心都是通过计算空间中点的距离来实现目的,只是他们的目的是不同的。KNN的最终目的是分类,而Kmeans的目的是给所有距离相近的点分配一个类别,也就是聚类

简单说,就是画一个圈,KNN是让进来圈子里的人变成自己人,Kmeans是让原本在圈内的人归成一类人

Reference:

[1]: https://blog.csdn.net/likika2012/article/details/39619687

[2]: https://www.cnblogs.com/listenfwind/p/10685192.html

[3]:《统计学习方法》李航第2版

[4]: https://blog.csdn.net/sinat_30353259/article/details/80901746

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值