机器学习实战---k近邻算法

kNN算法具体描述可以参见李航的《统计学习方法》

kNN算法的伪码过程如下:

(1)计算已知类别数据集中的点与当前点之间的距离;

(2)按照距离递增次序排序;

(3)选取与当前点距离最小的k个点;

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

(5)返回前k个点出现频率最高的类别作为当前点的预测分类;


kNN代码详解如下:

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]          #首先获取已知类别数据点的个数,既输入特征矩阵的行数

    diffMat = tile(inX, (dataSetSize,1)) - dataSet   

    #tile函数是numpy库中的一个模块,此处具体的功能是讲向量inX按照行方向重复dataSetSize次,列方向重复1次。

    sqDiffMat = diffMat**2          #求矩阵diffMat中每个元素的平方
    sqDistances = sqDiffMat.sum(axis=1)     #将矩阵sqDiffMat每一行求和
    distances = sqDistances**0.5    

    sortedDistIndicies = distances.argsort()    

    #argsort()函数是numpy的模块,此处用来返回distances元素从小到大排序好之后的索引

    classCount={}          #建立字典,将用来存放k个点中的标签种类和对应的出现次数
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]   #取到前k个点的类别
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1    

        #此句与循环结合,目的是用来统计某一类别标签在k个点中出现的次数

        #get函数,用来返回键voteIlabel的值,如果不存在,就返回0,如果存在就返回該值,并加1

    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)

    #sorted()函数用法:python的Build-in函数 sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list

        #iterable是可迭代类型;

        #cmp:用于比较的函数,比较什么由key决定;

        #key:用列表元素的某个属性或函数(此例中是函数)进行作为关键字,有默认值,迭代集合中的一项;

        #reverse:排序规则. reverse = True  降序 或者 reverse = False 升序,有默认值。

        #返回值:是一个经过排序的可迭代类型,与iterable一样。

    #iteritems()函数用法:此处将字典classCount转变成可迭代的对象,书上说是分解为元祖列表

    #operator.itemgetter(1):定义一个函数,用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号)

    return sortedClassCount[0][0]        #返回出现次数最大的那个类别标签

准备数据阶段:将文本文件转换成Numpy的解析程序:

def file2matrix(filename): #将文本记录转换为Numpy的解析程序
		fr=open(filename)   #打开文件,并且返回一个表示文件的对象
		arrayOLines = fr.readlines() #readlines()方法读取整个文件所有行,保存在一个列表(list)变量中,每行(字符串类型)作为一个元素,但读取大文件会比较占内存。
		numberOfLines = len(arrayOLines)  #获取列表的元素个数,既读入文件的行数
		returnMat = zeros((numberOfLines,3)) #zeros函数的返回对象是numpy中的array数组结构
		classLabelVector = [] #创建一个空列表,用来存放类别
		index = 0
		for line in arrayOLines:
			line = line.strip()  #删除每一行数据的头和尾的空格,line是类型是列表的元素,既是字符串
			listFromLine = line.split('\t')  #以制表符对字符串进行分割,将一个字符串分割成多个字符串组成的列表
			returnMat[index, : ] = listFromLine[0:3]  #将列表listFromLine前3个数据,赋给returnMat第index行的,前2列
			classLabelVector.append(int(lisFromLine[-1]))  #将每一行的最后一个数字(转化成整型),然后加入到列表里面
			index+=1
		return returnMat,classLabelVector    #返回存放特征的array数组(元素以字符串的类型存放),和存放类别的列表

由于各特征值之间的差异比较大,需要归一化,需要将每个点的三个特征值转化到(0,1)区间内:

def autoNorm(dataSet):  
		minVals=dataSet.min(0)
		maxVals=dataSet.max(0)
		ranges= maxVals-minVals
		normDataSet=zeros(shape(dataSet))
		m=dataSet.shape[0]  #返回dataSet第一维度的数目,既是行数
		normDataSet=dataSet-tile(minVals,(m,1))
		normDataSet=normDataSet/tile(range,(m,1))
		return normDataSet,ranges,minVals

一般用已有数据的90%作为训练样本,10%去测试分类器

def datingClassTest(): #测试代码
		hoRatio=0.10
		datingDataMat,datingLabels=file2matrix('datingTestSet.txt')
		normsMat,ranges,minVals=autoNorm(datingDataMat) #归一化特征矩阵
		m=normsMat.shape[0]
		numTestVecs=int(m*hoRatio)  #用来测试的数据的数量numTestVecs
		errorCount=0.0
		for i in range(numTestVecs):
			classifierResult=classify0(normMat[i, : ],normsMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
			#数据的前numTestVecs行用来测试,后面的剩下的用来训练
			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 classifyPerson():
		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')
		normsMat,ranges,minVals=autoNorm(datingDataMat) 
		inArr=array([ffMiles,percentTats,iceCream])
		classifierResult=classify0((inArr-minVals)/ranges,normsMat,datingLabels,3)
		print "You will probably like this person:",resultList[classifierResult-1]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值