K邻近算法

一 、什么是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,labels

def 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**2
	sqDistances=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]  
分类结果如图所示:



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值