KNN算法拓展及实现

编程入门 行业动态 更新时间:2024-10-10 12:20:18

KNN<a href=https://www.elefans.com/category/jswz/34/1770096.html style=算法拓展及实现"/>

KNN算法拓展及实现

前言

K近邻算法是一种思想极其简单,而分类效果比较优秀的分类算法,最重要的是该算法是很多高级机器学习算分基础,并且在后面我们将要学习的集成算法中,k近邻也经常被用来做基础分类器。它的基本思想我们已经在上节介绍过了,在此我们不在赘述,本节主要讲一下有关它的拓展知识以及实现。

模型:所有的空间划分,判别模型
策略:距离最近的k个邻居
方法:多数表决(注意,这里没有可计算的优化方法,可能我也没有说清楚,自己体会一下)
训练过程:交叉验证的方法,来调整k值得选择,使得最终的预测估计误差最小。

拓展

  KNN算法思想简单容易实现,但是它是一种没有优化(因为分类决策为多数投票)的暴力方法(线性搜索方法),所以当数据量比较大的时候,算法效率容易达到瓶颈。例如,样本个数为N,特征维数位D的时候,该算法的时间复杂度为O(D*N)。所以,通常情况下,KNN的实现会把训练数据建成Kd-tree(K-dimensional tree,kd-tree搜索方法),构建过程很快,甚至不用计算D为欧氏距离,而搜索速度高达O(D*log(N))。但是建立kd-tree搜索方法也有一个缺点是:当D维度过高的时候,会产生所谓的“维度灾难”,最终的效率会降低到与暴力法一样。
kd树更适合用于训练实例树远大于空间维数时的k近邻搜索。当空间维数接近于训练实例数的时候,它的效率会迅速下降,几乎接近于线性扫描。

  当维度D>20以后,最好使用更高效率的ball-tree, 其时间复杂度为仍为O(D*log(N))。

  人们经过长期的实践发现,KNN算法适用于样本分类边界不规则的情况。由于KNN主要依靠周围有限的邻近样本,而不是靠判别类域的方法来确定所属类别,因此对于类域的交叉或重叠较多的待分样本集来说,KNN算法比其他方法要更有效。

  该算法在分类时有个主要的不足是,当样本不平衡的时候,如果一个类的样本容量很大,而其他类样本容量很小的时候,有可能导致当输入一个新样本的时候,该样本的K个邻居中大容量类的样本占多数。因此可以采用权值的方法(和该样本距离小的邻居取值大)来改进。
  该方法的另一个不足之处是计算量比较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离(当然了我们也提到过多次kd-tree的优化算法,可以避免这种情况),才能求得它的K个最近邻。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。该算法比较适用于样本容量较大的类域的自动分类,而那些样本容量较小的类域采用这种方法比较容易产生误分。

算法描述

总的来说就是我们已经存在了一个带标签的数据库,然后输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似(最近邻)的分类标签。一般来说,只选择样本数据库中前k个最相似的数据。最后,选择k个最相似数据中出现次数最多的分类。其算法描述如下:

1)计算已知类别数据集中的点与当前点之间的距离;2)按照距离递增次序排序;3)选取与当前点距离最小的k个点;4)确定前k个点所在类别的出现频率;5)返回前k个点出现频率最高的类别作为当前点的预测分类。
#算法一 调用sklearn中的方法
# -*- encoding:utf-8-*-'''
调用sklearn中的方法,并且使用sklearn中自己的数据
@author:Ada
'''
print __doc__
import numpy as np
from sklearn import neighbors,datasets#下载数据
#64维 1797个样本
datas=datasets.load_digits()
totalNum=len(datas.data)#1797
#print totalNum
#print len(datas.data[0])#分割数据集
#选出80%样本作为训练集,剩余的20%作为测试集
trainNum=int(0.8*totalNum)
trainX=datas.data[0:trainNum]
trainY=datas.target[0:trainNum]
testX=datas.data[trainNum:]
testY=datas.target[trainNum:]#设置k值,一般情况下k<20
n_neighbors=10#建立分类器
clf=neighbors.KNeighborsClassifier(n_neighbors=n_neighbors,weights='uniform',algorithm='auto')
#训练分类器
clf.fit(trainX,trainY)#利用训练好的分类器进行预测
answer=clf.predict(testX)print "误分率为:%.2f%%"%((1-np.sum(answer==testY)/float(len(testY)))*100)#说明:
#KNeighborsClassifier可以设置3种算法:‘brute’,‘kd_tree’,‘ball_tree’。
#如果不知道用哪个好,设置‘auto’让KNeighborsClassifier自己根据输入去决定。

关于kd-tree和ball-tree基础参见这里

#方法二:自己实现一个线性KNN算法
from numpy import *
import operator#create a dataset which coantains 4 samples with 2 classesdef createDataSet():#create a matrix:each row as a samplegroup=array([[1.5,1.4],[1.6,1.5],[0.1,0.2],[0.0,0.1]])# each sample has two featureslabels=['A','A','B','B']#four samples with two labelsreturn group,labels#calssify using KNN
def KNNClassify(newInput,dataSet,labels,k):numSamples=dataSet.shape[0]#shape[0] stands for the num of row#Step 1:calculate Euclidean distance#tile(A,reps):construce an array by repeating A reps times# eg:#A=[[1.2,1.0]]#diff =tile(A,(4,3))#也就是说把A看成一个整体,把A赋值成4行3列# diff:#[[ 1.2  1.   1.2  1.   1.2  1. ]# [ 1.2  1.   1.2  1.   1.2  1. ]# [ 1.2  1.   1.2  1.   1.2  1. ]# [ 1.2  1.   1.2  1.   1.2  1. ]]#the following copy numSamples rows for dataSetdiff =tile(newInput,(numSamples,1))-dataSet#计算测试集与每个训练集的差值squareDiff=diff**2#差的平方squareDist=sum(squareDiff,axis=1)#按行求和,也就是对每个样本进行操作计算,平方和distance=squareDist**0.5#Step 2: sort the distance by asce#argsort() returns the distances that would sort an array in a ascending ordersortedDistance=argsort(distance)classCount={}#定义一个字典(对应到每个样本)for i in xrange(k):#Step 3:choose the min k distancevoteLabel=labels[sortedDistance[i]]# Step 4:count the times labels occur# when the key voteLabel is not in dictionary classCount ,get()# will return 0classCount[voteLabel]=classCount.get(voteLabel,0)+1# Step 5:the max voted class will returnmaxCount=0for key,value in classCount.items():if value>maxCount:maxCount=valuemaxIndex=keyreturn maxIndexif __name__ == '__main__':dataSet,labels=createDataSet()testData=array([1.2,1.0])k=3predictlabel=KNNClassify(testData,dataSet,labels,k)print '测试数据为:',testData,'预测结果类别为:',predictlabeltestData=array([0.1,0.3])predictlabel=KNNClassify(testData,dataSet,labels,k)print '测试数据为:',testData,'预测结果类别为:',predictlabel

实验结果为:

测试数据为: [ 1.2  1. ] 预测结果类别为: A
测试数据为: [ 0.1  0.3] 预测结果类别为: B

对于kd-tree搜索的KNN算法我们将在下节进行介绍。

《完》

所谓的不平凡就是平凡的N次幂。---- By Ada

更多推荐

KNN算法拓展及实现

本文发布于:2024-02-25 07:43:35,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1698261.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:算法   KNN

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!