K邻近算法

来源:互联网 发布:js工厂模式 编辑:程序博客网 时间:2024/03/29 23:21

一 、什么是K邻近算法?

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个(一般K是不大于20的整数)最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。


例如:有两类不同的样本数据,分别用蓝色的小正方形和红色的小三角形表示,而图正中间的那个绿色的圆所标示的数据则是待分类的数据。也就是说,现在, 我们不知道中间那个绿色的数据是从属于哪一类(蓝色小正方形or红色小三角形),下面,我们就要解决这个问题:给这个绿色的圆分类。
如果K=3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
如果K=5,绿色圆点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。

工作原理详细解释:一个样本数据集中每个样本都存在标签,也称作训练样本,即我们知道样本集中每一数据与所属分类的对应关系。然后输入没有标签的新数据(测试数据),将新数据的每个特征与样本集中数据对应的特征进行比较,然后用样本集中特征最享受的数据作为新数据的分类标签。

二 、算法的python编程

首先,我们创建名为kNN.py的python模块,代码如下:
# -*- coding: utf-8 -*-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,labelsdef classify0(intX,dataSet,labels,k):dataSetSize=dataSet.shape[0] #计算dataSet行数diffMat=tile(intX,(dataSetSize,1))-dataSet #tile():对intX按(4,1)进行复制,4代表复制4行,1代表列不变sqDiffMat=diffMat**2sqDistances=sqDiffMat.sum(axis=1)#sum(axis=1)按行求和distances=sqDistances**0.5#计算两个点间的距离sortedDistIndicies=distances.argsort()#argsort()按升序排序后取索引值classCount={}for i in range(k):voteIlabel=labels[sortedDistIndicies[i]]classCount[voteIlabel]=classCount.get(voteIlabel,0)+1#统计类别出现的次数{'A': 1, 'B': 2}sortedClassCount=sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)#将无序的字典迭代为有序的元组后,itemgetter(1)取出元组第二个域,并reverse=True按降序排序return sortedClassCount[0][0]

其中createDataSet()函数是创建数据集和分类标签,classify0()函数是使用K近邻算法将每组数据划分到某个类中,其伪代码为:

1)计算测试数据与各个训练数据之间的距离;

2)按照距离的递增关系进行排序;

3)选取距离最小的K个点;

4)确定前K个点所在类别的出现频率;

5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。

之后,在Python开发环境输入:

import kNN    group,labels = kNN.createDataSet()    kNN.classify0([0,0],group,lables,3)

便可以得到该样本数据属于B类。

三 、算法的应用

接下来我们通过一个实际的案例来更好的理解K近邻算法:约会网站的配对效果

样本数据集来源于1000行约会数据,主要包含以下三种特征:

(1)每年获得的飞行常客里程数

(2)玩视频游戏所耗时间百分比

(3)每周消费的冰淇淋公升数

首先,在数据添加到分类器前,我们要将数据处理为分类器可以接受的Numpy矩阵形式,输出为训练样本矩阵和类标签向量

def file2matrix(filename):#将分类数据转换为Numpy解析程序,这样便于分类器可接收    fr = open(filename)    numberOfLines = len(fr.readlines())         #读取文件,得到行数    returnMat = zeros((numberOfLines,3))        #先创建一个1000行,3列均为0的返回矩阵,用于接下来存放样本矩阵    classLabelVector = []                       #准备类标签数组      fr = open(filename)    index = 0    for line in fr.readlines():        line = line.strip()#去掉首尾空格        listFromLine = line.split('\t')        returnMat[index,:] = listFromLine[0:3]#取样本数据的前3列,存储到返回矩阵中        classLabelVector.append(int(listFromLine[-1]))#存储类标签到数组中

接着,因为样本特征数据的单位不统一,有的很大,有的很小,所以我们要归一化特征值,将所有特征值转化为(0,1)的数据,公式为newValue=(OldValue-min)/(max-min)

def autoNorm(dataSet):#归一化特征值,将所有特征值转化为(0,1)的数据,公式为newValue=(OldValue-min)/(max-min)    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
然后,我们从训练集选取10%的样本数据来测试算法的错误率

def datingClassTest():#分类器测试代码,一般选取10%的已知类别的样本数据进行测试    hoRatio = 0.10      #hold out 10%    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file    normMat, ranges, 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)#调用分类函数,返回实际分类的类别        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])        if (classifierResult != datingLabels[i]): errorCount += 1.0    print "the total error rate is: %f" % (errorCount/float(numTestVecs))    print errorCount
最后,我们使用算法,构建完整的分类器

def classiyPerson():      # 定义分类结果的类别      resultList = ['not at all','in small doses','in large doses']      # 读取输入数据      percentTats = float(raw_input("percentage of time spent playing video games?"))      ffMiles = float(raw_input("frequent flier miles earned per year?"))      iceCream = float(raw_input("liters of ice cream consumed per year?"))      # 从文件中读取已有数据      datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')      # 对数据进行归一化      normMat,ranges,minVals = autoNorm(datingDataMat)      # 将单个输入数据定义成一条数据      inArr =array([ffMiles,percentTats,iceCream])      # 对输入数据进行分类      classifierResult = classify0(inArr,datingDataMat,datingLabels,3)      # 输出预测的分类类别      print "You will probably like this person:",resultList[classifierResult - 1]  
分类结果如图所示:



原创粉丝点击