机器学习 & python 使用k-近邻算法改进约会网站的配对效果

参考自:《Machine Learning In Action》第二章


######################################################################


程序流程:

1.收集数据:提供文本文件

2.准备数据:使用Python解析文本文件

3.分析数据:使用Matplotlib画二维扩散图

4.测试算法:使用提供的部分数据作为测试样本。

测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误

5.使用算法:产生简单的命令行程序,然后可以输入一些特征数据以判断结果


###########################################################


本样本共有三种特征:

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

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

每周消费的冰淇淋公升数


数据存放在文本文件datingTestSet2.txt文件中,每个样本数据占据一行,总共有1000行

#!/usr/local/env python
#-*- coding: utf-8 -*-

from numpy import * #导入科学计算包numpy模块
import operator  #导入运算符模块

#k-近邻分类算法
def classify0(inX, dataSet, labels, k): #4个输入参数分别为:用于分类的输入向量inX,输入的训练样本集dataSet,标签向量labels,选择最近邻居的数目k
	#计算距离
	dataSetSize=dataSet.shape[0]  #获取数据集的宽
	diffMat=tile(inX, (dataSetSize, 1))-dataSet #使用欧式距离度量,故将输入向量和数据集中各向量相减
	sqDiffMat=diffMat**2  #平方
	sqDistances=sqDiffMat.sum(axis=1)  #计算输入向量和数据集中各向量之间的差的平方和
	distances=sqDistances**0.5  #计算欧式距离
	#选择距离最小的k个点 计算所属类别的出现频率
	sortedDistIndicies=distances.argsort() #取得输入向量和数据集中各向量欧式距离的从小到大排序的下标值
	classCount={}  #定义一个空字典
	for i in range(k):  #取计算欧氏距离排序后最小的前k个值
		voteIlabel=labels[sortedDistIndicies[i]]
		classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
	#排序 选择前k个点中出现最多的那一个类
	sortedClassCount=sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
	return sortedClassCount[0][0]

#将文本记录转换为Numpy的array
def file2matrix(filename): #输入为文件名字符串
	fr=open(filename) #打开文件
	arrayOLines=fr.readlines() #取得该文件的每行数据的列表
	numberOfLines=len(arrayOLines) #计算该文件共有多少行(即共有多少个样本)
	returnMat=zeros((numberOfLines, 3)) #创建返回的Numpy矩阵
	classLabelVector=[]
	index=0
	for line in arrayOLines: #解析文件数据到列表
		line=line.strip() #去掉首尾空白符
		listFromLine=line.split('\t') #利用空格符分离字符串
		returnMat[index, :]=listFromLine[0:3] #将每行样本数据的前3个数据输入返回样本矩阵中
		classLabelVector.append(int(listFromLine[-1]))  #将每行样本数据的最后一个数据加入类标签向量中
		index+=1 
	return returnMat, classLabelVector #返回训练样本矩阵和类标签向量

#归一化特征值
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)) #特征值相除
	return normDataSet, ranges, minVals #返回归一化矩阵,取值范围以及最小值

#测试程序
def datingClassTest():
	hoRatio=0.10 #取测试样本占数据集样本的10%
	datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') #得到样本集,样本标签
	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) #k-近邻算法
		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)) #计算错误率,并输出

#自定义分类器:输入信息并得出结果
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 filer miles earned per year?"))
	iceCream=float(raw_input("liters of icecream consumed per year?"))
	datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
	normMat,ranges,minVals=autoNorm(datingDataMat)
	inArr=array([ffMiles, percentTats, iceCream])
	classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
	print "You will probably like this person: ",resultList[classifierResult-1]


########################################################3
代码解析


在将上述特征数据输入到分类器之前,必须将待处理数据的格式改变为分类器可以接受的格式。

使用file2matrix函数,输入为文件名字符串,输出为训练样本矩阵和类标签向量



在处理不同取值范围的特征值时,通常将其数值归一化,如将取值范围处理为0到1或者-1到1之间。

下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:

newValues=(oldValues-min)/(max-min)

其中min和max分别是数据集中的最小特征值和最大特征值

使用函数autoNorm(),讲数字特征值转化为0到1区间


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值