K近邻算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K近邻算法相关的知识,希望对你有一定的参考价值。
概述
该算法采用测量不同特征值之间的距离方法进行分类。
优点:精度高,对异常值不敏感,无数据输入假定。
缺点:计算复杂度高,每次测试样本中的一个数据都要和训练样本所有数据进行距离计算,所以耗费的时间长,效率不高。空间复杂都高,需要存储大量数据,占用大量存储空间
使用数据范围:数值型,标称型(标称型数据要转化为数字型)
工作原理:算法要求存在一个训练样本数据集合,每个数据都有一个分类标签。输入测试数据后,将新输入样本每个特征值与训练样本特征进行比较,提取出训练样本中特征最相似数据的分类标签,而k表示提取出的分类标签数,可以自定义,根据计算错误率选择最优k值,最后在k个最相似数据中选择出现次数最多的分类,最为新数据的分类
算法一般流程
(1)收集数据:任何数据收集方法
(2)准备数据:将收集的数据整理为符合算法要求的结构化的数据格式
(3)分析数据:任何方法
(4)训练算法:不适用与K近邻算法
(5)测试算法:计算错误率
(6)使用算法:针对约会网站的数据分类,手写数字识别
准备数据:使用python导入数据
from numpy import * import operator #标准函数操作 def createDataSet(): group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) #矩阵,特征值量化,两个特征值 labels = [‘A‘, ‘A‘, ‘B‘, ‘B‘] # 列表,上述特征值对应的分类标签 return group, labels
我这里是使用的python3.6版本,个人喜欢用较新版本。注意:训练样本特征值以矩阵形式存储,行向量代表一个样本的特征数据,列向量代表一个特征的所有样本值(切记)
实施K近邻算法
def classify0(inx,dataSet,labels,k):# inx为用于分类的输入向量,dataSet为训练样本集,labels为标签向量 dataSetSize=dataSet.shape[0] diffMat=tile(inx,(dataSetSize,1))-dataSet #tile()函数将inx进行dataSetSize行,1列重复输出,最后减去dataSet训练集对应的数据 sqDiffMat=diffMat**2 #矩阵中每个数据点的平方 sqDistance=sqDiffMat.sum(axis=1) #axis=1表示计算矩阵每一行行向量的和 Distance=sqDistance**0.5 #行向量,转化为行向量 sortDistIndicies=Distance.argsort() #从小到大排序,返回排序后的数据点在原Distance中的索引 classCount={} for i in range(k): Votelabel=labels[sortDistIndicies[i]] classCount[Votelabel]=classCount.get(Votelabel,0)+1;#0为默认值 print(classCount) sortClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)#升序,sortClassCount为列表 return sortClassCount[0][0]
算法返回了一个新输入数据的分类结果,新数据与样本的相似性在这里用欧式距离公式衡量,即向量间的距离公式。为了预测数据所在分类,可以使用一下命令:
group,labels=createDataSet() print(classify0([0,0],group,labels,4))
分类器的性能(分类效果)受到多种因素的影响,如分类器设置,数据集等,为了测试分类器的效果,我们可以用分类器给出的测试结果与真实结果进行比较,计算出错误率——错误次数除以总的测试执行次数。
以改进约会网站的配对效果为例
数据来源链接:https://www.manning.com/books/machine-learning-in-action
要是我们想看一下数据的分布情况,可以用Matplotlib创建散点图
import matplotlib fig=plt.figure() ax=fig.add_subplot(111) ax.scatter(datingDataMat[:,1],datingDataMat[:,2],20*array(datinglabels),15*array(datinglabels)) plt.show()
准备数据:数值归一化
如果两特征值的数据大小相差很大时,我们可以用归一化将特征值转化为0到1之间
newValue=(oldValue-min)/(max-min)
下面是归一化特征值的代码:
def autoNorm(dataSet): minVals = dataSet.min(0)#每列选取最小数 maxVals = dataSet.max(0) ranges = maxVals - minVals normDataSet = zeros(shape(dataSet)) m = dataSet.shape[0] normDataSet = dataSet - tile(minVals, (m,1)) normDataSet = normDataSet/tile(ranges, (m,1)) #element wise divide return normDataSet, ranges, minVals#返回归一化后的数据矩阵,每个特征值的变动大小,特征值的最小值
测试算法:验证分类器
def datingClassTest(): hoRatio=0.1 datingDataMat,datinglabels=file2matrix(‘datingTestSet.txt‘) normMat,rangs,minVals=autoNorm(datingDataMat) m=normMat.shape(0) numTestVecs=int(m*hoRatio) errorCount=0.0; for i in range(numTestVecs): classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datinglabels[numTestVecs:m],3) if (classifierResult!=datinglabels[i]): errorCount+=1; print(errorCount/float(numTestVecs))#输出错误率
使用算法:构建完整的可用系统
通过下面的函数,用户可以输入三个特征值,程序会自动给出预测值
def classPerson(): resultList = [‘not at all‘, ‘in small doses‘, ‘in large doses‘] percentTats = float(input("percentage of time spent playing video games?")) ffMiles = float(input("frequent flier miles earned per year?")) iceCream = float(input("liters of ice cream consumed per year?")) datingDataMat, datinglabels = file2matrix(‘datingTestSet2.txt‘) normMat, rangs, minVals = autoNorm(datingDataMat) inArr=array([ffMiles,percentile,iceCream]) classifierResult=classify0((inArr-minVals)/rangs,normMat,datinglabels,3) print(resultList[classifierResult-1])
以上就是K近邻算法及其使用,该算法要求有接近实际数据的训练样本数据,同时,出了上面的缺点以外,该算法还有一个缺陷:无法给出任何数据的基础结构信息,因此我们不能知晓平均实例样本和典型样本具有的特征
以上是关于K近邻算法的主要内容,如果未能解决你的问题,请参考以下文章