机器学习中经常要用到分类算法,在诸多的分类算法中有一种算法名为k-近邻算法,也称为kNN算法。python
1、kNN算法的工做原理算法
2、适用状况app
3、算法实例及讲解机器学习
---1.收集数据函数
---2.准备数据学习
---3.设计算法分析数据测试
---4.测试算法网站
1、kNN算法的工做原理spa
官方解释:存在一个样本数据集,也称做训练样本集,而且样本中每一个数据都存在标签,即咱们知道样本集中每一数据与所属分类的对应关系,输入没有标签的新数据后,将新数据的每一个特征与样本集中的数据对应的特征进行比较,而后算法提取样本集中特征最类似的数据(最近邻)的分类标签。通常来讲,咱们只选择样本集中前k个最类似的数据,这就是k-近邻算法中k的出处,一般k是不大于20的整数,最后,选择k个最类似的数据中出现次数最多的分类,做为新数据的分类。设计
个人理解:k-近邻算法就是根据“新数据的分类取决于它的邻居”进行的,好比邻居中大多数都是退伍军人,那么这我的也极有多是退伍军人。而算法的目的就是先找出它的邻居,而后分析这几位邻居大多数的分类,极有可能就是它本省的分类。
2、适用状况
优势:精度高,对异常数据不敏感(你的类别是由邻居中的大多数决定的,一个异常邻居并不能影响太大),无数据输入假定;
缺点:计算发杂度高(须要计算新的数据点与样本集中每一个数据的“距离”,以判断是不是前k个邻居),空间复杂度高(巨大的矩阵);
适用数据范围:数值型(目标变量能够从无限的数值集合中取值)和标称型(目标变量只有在有限目标集中取值)。
3、算法实例及讲解
例子中的案例摘《机器学习实战》一书中的,代码例子是用python编写的(须要matplotlib和numpy库),不太重在算法,只要算法明白了,用其余语言都是能够写出来的:
海伦一直使用在线约会网站寻找合适本身的约会对象。尽管约会网站会推荐不一样的人选,但她没有从中找到喜欢的人。通过一番总结,她发现曾交往过三种类型的人:1.不喜欢的人(如下简称1);2.魅力通常的人(如下简称2) ;3.极具魅力的人(如下简称3)
尽管发现了上述规律,但海伦依然没法将约会网站推荐的匹配对象纳入恰当的分类。她以为能够在周一到周五约会哪些魅力通常的人,而周末则更喜欢与那些极具魅力的人为伴。海伦但愿咱们的分类软件能够更好的帮助她将匹配对象划分到确切的分类中。此外海伦还收集了一些约会网站不曾记录的数据信息,她认为这些数据更有助于匹配对象的归类。
咱们先提取一下这个案例的目标:根据一些数据信息,对指定人选进行分类(1或2或3)。为了使用kNN算法达到这个目标,咱们须要哪些信息?前面提到过,就是须要样本数据,仔细阅读咱们发现,这些样本数据就是“海伦还收集了一些约会网站不曾记录的数据信息”。好的,下面咱们就开始吧!
----1.收集数据
海伦收集的数据是记录一我的的三个特征:每一年得到的飞行常客里程数;玩视频游戏所消耗的时间百分比;每周消费的冰淇淋公升数。数据是txt格式文件,以下图,前三列依次是三个特征,第四列是分类(1:不喜欢的人,2:魅力通常的人,3:极具魅力的人),每一行表明一我的。
数据文档的下载连接是:http://pan.baidu.com/s/1jG7n4hS
----2.准备数据
何为准备数据?以前收集到了数据,放到了txt格式的文档中了,看起来也比较规整,可是计算机并不认识啊。计算机须要从txt文档中读取数据,并把数据进行格式化,也就是说存到矩阵中,用矩阵来承装这些数据,这样才能使用计算机处理。
须要两个矩阵:一个承装三个特征数据,一个承装对应的分类。因而,咱们定义一个函数,函数的输入时数据文档(txt格式),输出为两个矩阵。
代码以下:
1 def file2matrix(filename): 2 fr = open(filename) 3 numberOfLines = len(fr.readlines()) 4 returnMat = zeros((numberOfLines, 3)) 5 classLabelVector = [] 6 fr = open(filename) 7 index = 0 8 for line in fr.readlines(): 9 line = line.strip() 10 listFromLine = line.split('\t') 11 returnMat[index, :] = listFromLine[0:3] 12 classLabelVector.append(int(listFromLine[-1])) 13 index += 1 14 return returnMat, classLabelVector
简要解读代码:首先打开文件,读取文件的行数,而后初始化以后要返回的两个矩阵(returnMat、classLabelsVector),而后进入循环,将每行的数据各就各位分配给returnMat和classLabelsVector。
----3.设计算法分析数据
k-近邻算法的目的就是找到新数据的前k个邻居,而后根据邻居的分类来肯定该数据的分类。
首先要解决的问题,就是什么是邻居?固然就是“距离”近的了,不一样人的距离怎么肯定?这个有点抽象,不过咱们有每一个人的3个特征数据。每一个人可使用这三个特征数据来代替这我的——三维点。好比样本的第一我的就能够用(40920, 8.326976, 0.953952)来代替,而且他的分类是3。那么此时的距离就是点的距离:
A点(x1, x2, x3),B点(y1, y2, y3),这两个点的距离就是:(x1-y1)^2+(x2-y2)^2+(x3-y3)^2的平方根。求出新数据与样本中每一个点的距离,而后进行从小到大排序,前k位的就是k-近邻,而后看看这k位近邻中占得最多的分类是什么,也就得到了最终的答案。
这个处理过程也是放到一个函数里的,代码以下:
1 def classify0(inX, dataSet, labels, k): 2 dataSetSize = dataSet.shape[0] 3 diffMat = tile(inX, (dataSetSize,1)) - dataSet 4 sqDiffMat = diffMat**2 5 sqDistances = sqDiffMat.sum(axis=1) 6 distances = sqDistances**0.5 7 sortedDistIndicies = distances.argsort() 8 classCount={} 9 for i in range(k): 10 voteIlabel = labels[sortedDistIndicies[i]] 11 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 12 sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1), reverse=True) 13 return sortedClassCount[0][0]
简要解读代码:该函数的4个参数分别为新数据的三个特征inX、样本数据特征集(上一个函数的返回值)、样本数据分类(上一个函数的返回值)、k,函数返回位新数据的分类。第二行dataSetSize获取特征集矩阵的行数,第三行为新数据与样本各个数据的差值,第四行取差值去平方,以后就是再取和,而后平方根。代码中使用的排序函数都是python自带的。
好了,如今咱们能够分析数据了,不过,有一点不知道你们有没有注意,咱们回到那个数据集,第一列表明的特征数值远远大于其余两项特征,这样在求距离的公式中就会占很大的比重,导致两点的距离很大程度上取决于这个特征,这固然是不公平的,咱们须要的三个特征都均平地决定距离,因此咱们要对数据进行处理,但愿处理以后既不影响相对大小又能够不失公平:
这种方法叫作,归一化数值,经过这种方法能够把每一列的取值范围划到0~1或-1~1:,处理的公式为:
newValue = (oldValue - min)/(max - min)
归一化数值的函数代码为:
1 def autoNorm(dataSet): 2 minVals = dataSet.min(0) 3 maxVals = dataSet.max(0) 4 ranges = maxVals - minVals 5 normDataSet = zeros(shape(dataSet)) 6 m = dataSet.shape[0] 7 normDataSet = dataSet - tile(minVals, (m, 1)) 8 normDataSet = normDataSet / tile(ranges, (m, 1)) 9 return normDataSet, ranges, minVals
---4.测试算法
通过了格式化数据、归一化数值,同时咱们也已经完成kNN核心算法的函数,如今能够测试了,测试代码为:
1 def datingClassTest(): 2 hoRatio = 0.10 3 datingDataMat, datingLabels = file2matrix('datingTestSet.txt') 4 normMat, ranges, minVals = autoNorm(datingDataMat) 5 m = normMat.shape[0] 6 numTestVecs = int(m * hoRatio) 7 errorCount = 0.0 8 for i in range(numTestVecs): 9 classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3) 10 print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]) 11 if (classifierResult != datingLabels[i]): errorCount += 1.0 12 print "the total error rate is: %f" % (errorCount / float(numTestVecs))
经过测试代码咱们能够在回忆一下这个例子的总体过程:
代码中你们可能不太明白hoRatio是什么。注意,这里的测试数据并非另一批数据而是以前的数据集里的一部分,这样咱们能够把算法获得的结果和本来的分类进行对比,查看算法的准确度。在这里,海伦提供的数据集又1000行,咱们把前100行做为测试数据,后900行做为样本数据集,如今你们应该能够明白hoRatio是什么了吧。
总体的代码:
1 from numpy import * 2 import operator 3 4 def classify0(inX, dataSet, labels, k): 5 dataSetSize = dataSet.shape[0] 6 diffMat = tile(inX, (dataSetSize,1)) - dataSet 7 sqDiffMat = diffMat**2 8 sqDistances = sqDiffMat.sum(axis=1) 9 distances = sqDistances**0.5 10 sortedDistIndicies = distances.argsort() 11 classCount={} 12 for i in range(k): 13 voteIlabel = labels[sortedDistIndicies[i]] 14 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 15 sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1), reverse=True) 16 return sortedClassCount[0][0] 17 18 def file2matrix(filename): 19 fr = open(filename) 20 numberOfLines = len(fr.readlines()) 21 returnMat = zeros((numberOfLines, 3)) 22 classLabelVector = [] 23 fr = open(filename) 24 index = 0 25 for line in fr.readlines(): 26 line = line.strip() 27 listFromLine = line.split('\t') 28 returnMat[index, :] = listFromLine[0:3] 29 classLabelVector.append(int(listFromLine[-1])) 30 index += 1 31 return returnMat, classLabelVector 32 33 def autoNorm(dataSet): 34 minVals = dataSet.min(0) 35 maxVals = dataSet.max(0) 36 ranges = maxVals - minVals 37 normDataSet = zeros(shape(dataSet)) 38 m = dataSet.shape[0] 39 normDataSet = dataSet - tile(minVals, (m, 1)) 40 normDataSet = normDataSet / tile(ranges, (m, 1)) 41 return normDataSet, ranges, minVals 42 43 def datingClassTest(): 44 hoRatio = 0.10 45 datingDataMat, datingLabels = file2matrix('datingTestSet.txt') 46 normMat, ranges, minVals = autoNorm(datingDataMat) 47 m = normMat.shape[0] 48 numTestVecs = int(m * hoRatio) 49 errorCount = 0.0 50 for i in range(numTestVecs): 51 classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3) 52 print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]) 53 if (classifierResult != datingLabels[i]): errorCount += 1.0 54 print "the total error rate is: %f" % (errorCount / float(numTestVecs))
运行一下代码,这里我使用的是ipython:
最后的错误率为0.05。