目录
K-近邻算法实战(二):约会网站配对效果判断
实战
1.背景介绍
2.准备数据:数据分类
3.分析数据:数据可视化
4.准备数据:数据归一化
5.测试算法:验证分类器
6.使用算法:构建完整可用系统
K-近邻算法实战(二):约会网站配对效果判断
一般的K-近邻算法流程:
1.收集数据:方法有爬虫进行数据收集或是使用第三方提供的数据
2.准备数据:用Python解析、预处理数据
3.分析数据:对数据进行分析,例如使用Matplotlib将数据可视化
4.测试算法:计算算法的错误率
5.使用算法:在错误率可接受的范围内,运用k-近邻算法进行分类
实战
1.背景介绍
线上网站寻找适合自己的约会对象,海伦女士对自己的喜好进行一番总结,她发现可以将交往过的人进行如下分类:
1.不喜欢的人
2.魅力一般的人
3.极具魅力的人
海伦收集交往过的人的数据主要包含3个特征:
1.每年获得的飞行常客里程数
2.玩视频游戏所消耗时间百分比
3.每周消耗的冰淇淋公升数
采用的数据集包含三个特征和一个喜欢的类型,放在文本文件datingTesingSet.txt中,数据下载:Machine-Learning/datingTestSet.txt at master · Jack-Cherish/Machine-Learning ()
文件中的数据格式如下:
2.准备数据:数据分类
在机器学习:K-近邻算法(一)_晶哥哥&的博客-CSDN博客中,学习了K-近邻算法的代码实现,就是写成了分类器,那么要使用分类器就要将待处理的数据格式改变为分类器能接受的格式,即特征矩阵和分类标签向量。
(1)编写代码如下:
'''函数说明:对数据进行分类:1代表不喜欢,2代表魅力一般,3代表极具魅力输入:文件名(filename)输出:特征矩阵(returnMat)、分类标签(classLabelVector)'''def file2matrix(filename):#打开文件file=open(filename)#得到文件的所有内容arrayofLines=file.readlines()#得到文件的行数numberofLines=len(arrayofLines)#初始化返回的特征矩阵,注意这里函数里边的矩阵类型必须加括号returnMat=np.zeros((numberofLines,3))#初始化分类标签向量calssLabelVector=[]#行的索引值index=0for line in arrayofLines:#删除每一行的首尾空白符line=line.strip()#将每一行的内容按照分隔符切片listFormLine=line.split('\t')#将切片后的列表中前三行内容存放到特征矩阵中returnMat[index,:]=listFormLine[0:3]#将文本中的喜欢程度进行分类if listFormLine[-1]=='didntLine':classLabelVector.append(1)elif listFormLine[-1]=='smallDoses':classLabelVector.append(2)elif listFormLine[-1]=='largeDoses':listLabelVector.append(3)index+=1return returnMat,classLabelVector
(2)不会的知识点:
A.文件的readlines()
返回一个列表,将文件中的每一行作为一个列表项
例如:x.txt文件的内容为:
B.字符串的strip()方法
用于删除字符串首尾指定的字符(参数为空时,默认删除空白符,包括:‘\t’,‘\n’,‘\r’,‘ ’)或序列
C.字符串的split()方法
通过指定分隔符来对字符串进行切片
split(str='',num=string.count(str))
str----分隔符,默认为所有空白符,包括:空格、换行、制表符等
num--分割次数,默认为-1,即分割所有
返回值:返回切片后的字符串的列表
(3)测试效果如下:
3.分析数据:数据可视化
将数据进行可视化的方式展示,方便进行观察
(1)编写的代码如下:
'''函数说明:可视化数据输入:特征矩阵(datingDataMat)、分类标签向量(datingLables)'''def showdatas(datingDataMat,datingLabels):#设置汉字格式font=FontProperties(fname=r'c:\windows\fonts\simsun.ttc',size=14)#创建画布,将fig画布分割成1行1列,不共享x轴y周,fig画布的到校为(13,8)#nrow=2,ncols=2,代表将fig画布分为四个区域,axs[0][0]表示第一行第一个区域fig,axs=plt.subplots(nrows=2,ncols=2,sharex=False,sharey=False,figsize=(13,8))numberofLabels=len(datingDataMat)LabelsColors=[]#设置标签颜色for i in datingLabels:if i==1:LabelsColors.append('black')if i==2:LabelsColors.append('orange')if i==3:LabelsColors.append('red')#画出散点图1,以特征矩阵的第一列和第二列数据画散点,散点大小为15axs[0][0].scatter(x=datingDataMat[:,0],y=datingDataMat[:,1],color=LabelsColors,s=15,alpha=0.5)#设置标题,x轴label,y轴labelaxs0_title_text=axs[0][0].set_title(u'每年获得的飞行常客里程数与玩视频游戏所消耗时间占比',FontProperties=font)axs0_xlabel_text=axs[0][0].set_xlabel(u'每年获得的飞行常客里程数',FontProperties=font)axs0_ylabel_text=axs[0][0].set_ylabel(u'玩视频游戏所消耗时间占比',FontProperties=font)#设置对象属性plt.setp(axs0_title_text,size=9,weight='blod',color='red')plt.setp(axs0_xlabel_text,size=9,weight='blod',color='black')plt.setp(axs0_ylabel_text,size=9,weight='blod',color='black')#画出散点图2,以特征矩阵的第一列和第三列数据画散点,散点大小为15axs[0][1],scatter(x=datingDataMat[:,0],y=datingDataMat[:,2],s=15,alpha=0.5)#设置标题,x轴label,y轴labelaxs1_title_text=axs[0][1].set_title(u'每年获得的飞行常客里程数与每周消耗的冰淇淋公升数',FontProperties=font)axs1_xlabel_text=axs[0][1].set_xlabel(u'每年获得的飞行常客里程数',FontPreperties=font)axs1_ylabel_text=axs[0][1].set_ylabel(u'每周消耗的冰淇淋公升数',FontProperties=font)#设置对象属性plt.setp(axs1_title_text,size=9,weight='blod',color='red')plt.setp(axs1_xlabel_text,size=9,weight='blod',color='black')plt.setp(axs1_ylabel_text,size=9,weight='blod',color='black')#画出散点图3,以特征矩阵的第二列和第三列数据画散点,散点大小为15axs[1][0].scatter(x=datingDataMat[:,1],y=datingDataMat[:,2],s=15,alpha=0.5)#设置标题,x轴label,y轴labelaxs2_title_text=axs[1][0].set_title(u'玩视频游戏所消耗时间占比与每周消耗的冰淇淋公升数',FontProperties=font)axs2_xlabel_text=axs[1][0].set_xlabel(u'玩视频游戏所消耗时间占比',FontProperteis=font)axs2_ylabel_text=axs[1][0],set_ylabel(u'每周消耗的冰淇淋公升数',FontProperties=font)#设置对象属性plt.setp(set_title_text,size=9,weight='blod',color='red')plt.setp(set_xlabel_text,size=9,weight='blod',color='black')plt.setp(set_ylavel_text,size=9,weight='blod',color='black')#设置图例didntLike=mlines.Line2D([],[],color='black',marker='.',markersize=6,label='didntLike')smallDoses=mlines.Line2D([],[],color='orange',marker='.',markersize=6,label='smallDoses')largeDoses=mlines.Line2D([],[],color='red',marker='.',markersize=6,label='largeDoses')#添加图例axs[0][0].legend(handles=[didntLike,smallDoses,largeDoses])axs[0][1].legend(handles=[didntLike,smallDoses,largeDoses])axs[1][0].legend(handles=[didntLike,smallDoses,largeDoses])#显示图片plt.show()
(2)不会的知识点
A.字符串前缀符r和u
在字符串前加r,表明这些字符是原生字符
对于原生字符的理解跟转义字符有关:
在字符串前加u,python2中用在字符串前,放置中文乱码,python3中所有的字符串默认都是unicode字符串
B.画散点图,使用创建子图的scattor()时,设置散点大小的关键字是s,不是size
C.plt.setp()用于设置对象属性
(3)代码实现结果如下:
4.准备数据:数据归一化
为什么要进行数据归一化?计算下面样本1和样本2之间的距离,使用欧式距离公式。
计算公式为:
从公式上可以看出,数字差值越大对计算结果影响越大,那么对于本项目来说,顾客飞行里程数这一特征比其他两个特征对结果的影响大且远远大,出现这样情况的原因是由于,飞行里程数的数量级远远大于另外两个特征,对于海伦来说三个特征同等重要。
处理这种不同取值范围的特征时,通常采用将数据归一化,将任意取值范围的特征值转化为0到1之间或-1到1之间,本次采用0到1之间。
newValue=(oldValue-min)/(max-min)
注:改变数值的取值范围会增加分类器的复杂度,但为了得到准确结果,必须这样做。
(1)编写代码如下:
'''函数说明:将训练集的数据进行归一化输入:特征矩阵(dataSet)输出:归一化后的特征矩阵(normDataSet)数据范围(ranges)数据最小值(minVals)'''def autoNorm(dataSet):#获取数据的最大值和最小值minVals=dataSet.min(0)maxVals=dataSet.max(0)#获取最大值和最小值的范围ranges=maxVals-minVals#初始化归一化后的特征矩阵normDataSet=np.zeros(np.shape(dataSet))#获取dataSet的行数m=dataSet.shape[0]#原数据减去最小值normDataSet=dataSet-np.tile(minVals,(m,1))#再除以最大值与最小值的差normDataSet=normDataSet/np.tile(ranges,(m,1))#返回归一化后的特征值,数据范围,最小值return normDataSet,ranges,minVals
(2)不会的知识点:
A.列表的内置函数min()和max()
对于列表---->max(list)得到列表中最大的值,min()也是
对于二维矩阵--->假如x是一个4行3列的二维矩阵
x.mix(0)返回的列表是由每一列中的最小元素组成的,列表中元素个数为3
x.min(1)返回的列表是由每一行中的最小元素组成的,列表中元素个数为4
B.numpy的shape()
np.shape(x)返回x矩阵的行数和列数
x.shape[0]返回x矩阵的行数
x.shape[1]返回x矩阵的列数
(3)测试效果如下:
5.测试算法:验证分类器
机器学习算法对于评估算法正确率的缓解是必不可少的,通常我们会将训练样本的90%的数据来训练分类器,其余10%用来测试分类器,注意10%的测试数据应该是随机选择的。
(1)编写代码如下:
'''函数说明:测试算法的正确率输入:无输出:打印出正确率注:这里调用前面写好的代码块分类特征矩阵和标签向量的函数---file2matrix(filename)将数据归一化的函数---autoNorm(datingSet)分类器函数(在前一篇文章KNN(一)中)----classify0(inX,dataSet,labels,k)'''def datingClassTest():filename='datingTestSet.txt'#获取特征矩阵和分类标签向量datingDataMat,datingLabels=file2matrix(filename)#设置测试数据百分比hoRatio=0.10#将数据归一化,返回归一化后的矩阵,数据范围,数据最小值normMat,ranges,minVals=autoNorm(datingDataMat)#获取数据的行数m=datingDataMat.shape[0]#得到测试数据的个数numTestVecs=int(m*hoRatio)#初始化错误分类计数errorCount=0.0for i in range(numTestVecs):#前numTestVecs个数据作为测试集,后面的数据做训练集classifierResult=classify0(normMat[i,:],normMat[numTestVecs:,:],datingLabels[numTestVecs:],4)print('分类结果:%d\t真是类别:%d'%(classifierResult,datingLabels[i]))if classifierResult!=datingLabels[i]:erroeCount+=1.0#%%是指字符'%'print('错误率:%f%%'%(errorCount/float(numTestVecs)*100))
(2)测试结果:
通过修改k值和训练集与测试集所占比例会改变错误率。
6.使用算法:构建完整可用系统
将前面写的代码段进行整合,写成一个小程序,海伦在网站上将某人的三个特征信息输入,程序就会给出喜欢程度的预测值。
(1)编写的代码如下:
'''函数说明:KNN算法,分类器'''import numpy as npdef classify0(inX,dataSet,labels,k):#获取dataSet的行数dataSize=dataSet.shape[0]diffMat=np.tile(inX,(dataSize,1))-dataSetsqDiffMat=diffMat**2sqDistances=sqDiffMat.sum(axis=1)distances=sqDistances**0.5#将计算出的距离元素进行排序,获得排序后的索引值sortedDistIndices=distances.argsort()#记录类别次数classCount={}for i range(k):#取出前K个元素的类别voteIlabel=labels[sortedDistIndices[i]]#计算类别次数classCount[voteIlabel]=classCount.get(voteIlabel,0)+1sortedClassCount=sorted(classCount,items(),key=operator.itemgetter(1),reverse=True)return sortedClassCount[0][0]'''函数说明:将数据进行分类,1代表不喜欢,2代表魅力一般,3代表极具魅力分类为:特征矩阵和分类标签向量'''def file2matrix(filename):#打开文件file=open(filename)#将数据存放在数组中arrayoLines=file.readlines()#获取数据的行数numberofLines=len(arrayoLines)#初始化特征矩阵returnMat=np.zeros((numberofLines,3))#初始化分类标签向量classLabelVector=[]#行的索引值index=0for line in arrayoLines:#清除首尾空白符line=line.strip()#将数据切片listFormLine=line.split('/t')#将前三列数据存放到特征矩阵中returnMat[index,:3]=listFormLine[:3]#将标签分类if listFormLine[-1]=='didntLike':classLabelVector.append(1)elif listFormLine[-1]=='smallDoses':classLabelVector.append(2)elif listFormLine[-1]=='largeDoses':classLabelVector.append(3)index+=1return returnMat,classLabelVector'''函数说明:将数据归一化'''def autoNorm(dataSet):#获取最大值和最小值minVals=dataSet.min(0)maxVals=dataSet.max(0)#得到数据范围ranges=maxVals-minVals#初始化归一化后的特征矩阵normDataSet=np.zeros(np.shape(dataset))#获取数据的行数m=dataSet.shape[0]normDataSet=dataSet-np.tile(minVals,(m,1))normDataSet=normDataSet/np.tile(ranges,(m,1))#返回归一化后的矩阵,数据范围,最小值return normDataSet,ranges,minVals'''函数说明:使用算法测试'''def classifyPerson():#输出结果列表result=['讨厌','有些喜欢','非常喜欢']#输入三个特征的数据ffMiles=float(input('每年获得的飞行常客里程数:'))precentTats=float(input('玩视频游戏所消耗时间占比:'))iceCream=float(imput('每周消耗的冰淇淋公升数:'))#文件名filename='datingTestSet.txt'#分类数据datingDataMat,datingLabels=file2matrix(filename)#将数据归一化normMat,ranges,minVals=autoNorm(datingDataMat)#生成测试集数组inArr=np.array([ffMiles,precentTats,iceCream])#将测试集数据归一化norminArr=(inArr-minVals)/ranges#调用分类器classifierResult=classify0(norminArr,normMat,datingLabels,3)#打印结果print('你可能%s这个人'%(result[classifierResult-1]))if __name__=='__main__':classifyPerson()
(2)测试结果如下:
批注:我学习的博主Jack Cui,网址:Jack Cui | 关注人工智能及互联网的个人网站 ()
我就是看他的学习记录学习的,详细学习内容可进入他的网站学习。我写文章主要目的是为了再次熟悉代码和记录不会的知识点。