KNN算法项目实战——改进约会网站的配对效果
Posted asialee
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KNN算法项目实战——改进约会网站的配对效果相关的知识,希望对你有一定的参考价值。
KNN项目实战——改进约会网站的配对效果
1、项目背景:
海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结,她发现自己交往过的人可以进行如下分类:
- 不喜欢的人
- 魅力一般的人
- 极具魅力的人
2、项目数据
海伦收集约会数据已经有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,每个样本数据占据一行,总共有1000行。
海伦收集的样本数据主要包含以下3种特征:
- 每年获得的飞行常客里程数
- 玩视频游戏所消耗时间百分比
- 每周消费的冰淇淋公升数
数据格式如下:
3、K-近邻算法的一般流程
(1)收集数据:提供文本文件。
(2)准备数据:使用Python解析文本文件。
(3)分析数据:使用Matplotlib画二维扩散图。
(4)测试算法:使用文本文件的部分数据作为测试样本,计算错误率。
(5)使用算法:错误率在可接受范围内,就可以运行k-近邻算法进行分类。
4、项目步骤及代码实现
1 #-*- coding:utf-8 -*- 2 3 import matplotlib.lines as mlines 4 import matplotlib.pyplot as plt 5 import numpy as np 6 import matplotlib as mpl 7 import operator 8 9 ‘‘‘ 10 #准备数据,从文本文件中解析数据 11 ‘‘‘ 12 def file2matrix(filename): 13 #打开文件 14 with open(filename,‘r‘) as fr: 15 # 读取文件所有内容 16 arrayOLines = fr.readlines() 17 # 得到文件行数 18 numberOfLines = len(arrayOLines) 19 # 返回的NumPy矩阵,解析完成的数据:numberOfLines行,3列 20 returnMat = np.zeros((numberOfLines, 3)) 21 # 返回的分类标签向量 22 classLabelVector = [] 23 # 行的索引值 24 index = 0 25 for line in arrayOLines: 26 # s.strip(rm),当rm空时,默认删除空白符(包括‘ ‘,‘ ‘,‘ ‘,‘ ‘) 27 line = line.strip() 28 # 使用s.split(str="",num=string,cout(str))将字符串根据‘ ‘分隔符进行切片。 29 listFromLine = line.split(‘ ‘) 30 # 将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵 31 returnMat[index, :] = listFromLine[0:3] 32 # 根据文本中标记的喜欢的程度进行分类,1代表不喜欢,2代表魅力一般,3代表极具魅力 33 if listFromLine[-1] == ‘didntLike‘: 34 classLabelVector.append(1) 35 elif listFromLine[-1] == ‘smallDoses‘: 36 classLabelVector.append(2) 37 elif listFromLine[-1] == ‘largeDoses‘: 38 classLabelVector.append(3) 39 index += 1 40 return returnMat, classLabelVector 41 42 43 44 ‘‘‘ 45 #分析数据,数据可视化,使用Matplotlib创建散点图 46 ‘‘‘ 47 def showdatas(datingDataMat, datingLabels): 48 #设置汉字格式 49 # sans-serif就是无衬线字体,是一种通用字体族。 50 # 常见的无衬线字体有 Trebuchet MS, Tahoma, Verdana, Arial, Helvetica, 中文的幼圆、隶书等等 51 mpl.rcParams[‘font.sans-serif‘] = [‘SimHei‘] # 指定默认字体 SimHei为黑体 52 mpl.rcParams[‘axes.unicode_minus‘] = False # 用来正常显示负号 53 #将fig画布分隔成2行2列,不共享x轴和y轴,fig画布的大小为(13,8) 54 #当nrow=2,nclos=2时,代表fig画布被分为四个区域,axs[0][0]表示第一行第一个区域 55 fig, axs = plt.subplots(nrows=2, ncols=2,sharex=False, sharey=False, figsize=(13,9)) 56 57 LabelsColors = [] 58 for i in datingLabels: 59 if i == 1: 60 LabelsColors.append(‘black‘) 61 if i == 2: 62 LabelsColors.append(‘orange‘) 63 if i == 3: 64 LabelsColors.append(‘red‘) 65 66 #画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第二列(玩游戏)数据画散点数据,散点大小为15,透明度为0.5 67 axs[0][0].scatter(x=datingDataMat[:,0], y=datingDataMat[:,1], color=LabelsColors,s=15, alpha=.5) 68 #设置标题,x轴label,y轴label 69 axs0_title_text = axs[0][0].set_title(‘每年获得的飞行常客里程数与玩视频游戏所消耗时间占比‘) 70 axs0_xlabel_text = axs[0][0].set_xlabel(‘每年获得的飞行常客里程数‘) 71 axs0_ylabel_text = axs[0][0].set_ylabel(‘玩视频游戏所消耗时间占‘) 72 plt.setp(axs0_title_text, size=12, weight=‘bold‘, color=‘red‘) 73 plt.setp(axs0_xlabel_text, size=10, weight=‘bold‘, color=‘black‘) 74 plt.setp(axs0_ylabel_text, size=10, weight=‘bold‘, color=‘black‘) 75 76 #画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5 77 axs[0][1].scatter(x=datingDataMat[:,0], y=datingDataMat[:,2], color=LabelsColors,s=15, alpha=.5) 78 #设置标题,x轴label,y轴label 79 axs1_title_text = axs[0][1].set_title(‘每年获得的飞行常客里程数与每周消费的冰激淋公升数‘,) 80 axs1_xlabel_text = axs[0][1].set_xlabel(‘每年获得的飞行常客里程数‘) 81 axs1_ylabel_text = axs[0][1].set_ylabel(‘每周消费的冰激淋公升数‘) 82 plt.setp(axs1_title_text, size=12, weight=‘bold‘, color=‘red‘) 83 plt.setp(axs1_xlabel_text, size=10, weight=‘bold‘, color=‘black‘) 84 plt.setp(axs1_ylabel_text, size=10, weight=‘bold‘, color=‘black‘) 85 86 #画出散点图,以datingDataMat矩阵的第二(玩游戏)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5 87 axs[1][0].scatter(x=datingDataMat[:,1], y=datingDataMat[:,2], color=LabelsColors,s=15, alpha=.5) 88 #设置标题,x轴label,y轴label 89 axs2_title_text = axs[1][0].set_title(‘玩视频游戏所消耗时间占比与每周消费的冰激淋公升数‘) 90 axs2_xlabel_text = axs[1][0].set_xlabel(‘玩视频游戏所消耗时间占比‘) 91 axs2_ylabel_text = axs[1][0].set_ylabel(‘每周消费的冰激淋公升数‘) 92 plt.setp(axs2_title_text, size=12, weight=‘bold‘, color=‘red‘) 93 plt.setp(axs2_xlabel_text, size=10, weight=‘bold‘, color=‘black‘) 94 plt.setp(axs2_ylabel_text, size=10, weight=‘bold‘, color=‘black‘) 95 96 #设置图例 97 didntLike = mlines.Line2D([], [], color=‘black‘, marker=‘.‘, markersize=6, label=‘不喜欢‘) 98 smallDoses = mlines.Line2D([], [], color=‘orange‘, marker=‘.‘,markersize=6, label=‘魅力一般‘) 99 largeDoses = mlines.Line2D([], [], color=‘red‘, marker=‘.‘,markersize=6, label=‘极具魅力‘) 100 #添加图例 101 axs[0][0].legend(handles=[didntLike,smallDoses,largeDoses]) 102 axs[0][1].legend(handles=[didntLike,smallDoses,largeDoses]) 103 axs[1][0].legend(handles=[didntLike,smallDoses,largeDoses]) 104 #显示图片 105 plt.show() 106 107 108 109 ‘‘‘ 110 #准备数据,数据归一化处理 111 ‘‘‘ 112 def autoNorm(dataSet): 113 #获得每列数据的最小值和最大值 114 minVals = dataSet.min(0) 115 maxVals = dataSet.max(0) 116 #最大值和最小值的范围 117 ranges = maxVals - minVals 118 #shape(dataSet)返回dataSet的矩阵行列数 119 #normDataSet = np.zeros(np.shape(dataSet)) 120 #返回dataSet的行数 121 m = dataSet.shape[0] 122 #原始值减去最小值 123 normDataSet = dataSet - np.tile(minVals, (m, 1)) 124 #除以最大和最小值的差,得到归一化数据 125 normDataSet = normDataSet / np.tile(ranges, (m, 1)) 126 #返回归一化数据结果,数据范围,最小值 127 return normDataSet, ranges, minVals 128 129 130 131 ‘‘‘ 132 KNN算法分类器 133 # inX - 用于分类的数据(测试集) 134 # dataSet - 用于训练的数据(训练集) 135 # labes - 训练数据的分类标签 136 # k - kNN算法参数,选择距离最小的k个点 137 # sortedClassCount[0][0] - 分类结果 138 ‘‘‘ 139 def classify0(inX, dataSet, labels, k): 140 #numpy函数shape[0]返回dataSet的行数 141 dataSetSize = dataSet.shape[0] 142 #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向) 143 diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet 144 #二维特征相减后平方 145 sqDiffMat = diffMat**2 146 #sum()所有元素相加,sum(0)列相加,sum(1)行相加 147 sqDistances = sqDiffMat.sum(axis=1) 148 #开方,计算出距离 149 distances = sqDistances**0.5 150 #返回distances中元素从小到大排序后的索引值 151 sortedDistIndices = distances.argsort() 152 #定一个记录类别次数的字典 153 classCount = {} 154 for i in range(k): 155 #取出前k个元素的类别 156 voteIlabel = labels[sortedDistIndices[i]] 157 #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。 158 #计算类别次数 159 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 160 #python3中用items()替换python2中的iteritems() 161 #key=operator.itemgetter(1)根据字典的值进行排序 162 #key=operator.itemgetter(0)根据字典的键进行排序 163 #reverse降序排序字典 164 sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) 165 #返回次数最多的类别,即所要分类的类别 166 return sortedClassCount[0][0] 167 168 169 170 ‘‘‘ 171 #测试算法,计算分类器的准确率,验证分类器 172 ‘‘‘ 173 def datingClassTest(): 174 #打开的文件名 175 filename = "datingTestSet.txt" 176 #将返回的特征矩阵和分类向量分别存储到datingDataMat和datingLabels中 177 datingDataMat, datingLabels = file2matrix(filename) 178 #取所有数据的百分之十 179 hoRatio = 0.10 180 #数据归一化,返回归一化后的矩阵,数据范围,数据最小值 181 normMat, ranges, minVals = autoNorm(datingDataMat) 182 #获得normMat的行数 183 m = normMat.shape[0] 184 #百分之十的测试数据的个数 185 numTestVecs = int(m * hoRatio) 186 #分类错误计数 187 errorCount = 0.0 188 189 for i in range(numTestVecs): 190 #前numTestVecs个数据作为测试集,后m-numTestVecs个数据作为训练集 191 classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],datingLabels[numTestVecs:m], 4) 192 print("分类结果:%d 真实类别:%d" % (classifierResult, datingLabels[i])) 193 if classifierResult != datingLabels[i]: 194 errorCount += 1.0 195 print("错误率:%f%%" %(errorCount/float(numTestVecs)*100)) 196 197 198 199 ‘‘‘ 200 #使用算法,构建完整可用系统 201 ‘‘‘ 202 def classifyPerson(): 203 #输出结果 204 resultList = [‘不喜欢‘,‘有些喜欢‘,‘非常喜欢‘] 205 #三维特征用户输入 206 ffMiles = float(input("每年获得的飞行常客里程数:")) 207 precentTats = float(input("玩视频游戏所耗时间百分比:")) 208 iceCream = float(input("每周消费的冰激淋公升数:")) 209 #打开的文件名 210 filename = "datingTestSet.txt" 211 #打开并处理数 据 212 datingDataMat, datingLabels = file2matrix(filename) 213 #训练集归一化 214 normMat, ranges, minVals = autoNorm(datingDataMat) 215 #生成NumPy数组,测试集 216 inArr = np.array([ffMiles,precentTats, iceCream]) 217 #测试集归一化 218 norminArr = (inArr - minVals) / ranges 219 #返回分类结果 220 classifierResult = classify0(norminArr, normMat, datingLabels, 3) 221 #打印结果 222 print("你可能%s这个人" % (resultList[classifierResult-1])) 223 224 225 226 ‘‘‘ 227 #主函数,测试以上各个步骤,并输出各个步骤的结果 228 ‘‘‘ 229 if __name__ == ‘__main__‘: 230 #打开的文件名 231 filename = "datingTestSet.txt" 232 #打开并处理数据 233 datingDataMat, datingLabels = file2matrix(filename) 234 #数据可视化 235 showdatas(datingDataMat, datingLabels) 236 #验证分类器 237 datingClassTest() 238 #使用分类器 239 classifyPerson()
5、项目结果
(1)数据可视化结果
(2)验证分类器计算错误率结果
(3)使用分类器根据输入数据获得预测结果
以上是关于KNN算法项目实战——改进约会网站的配对效果的主要内容,如果未能解决你的问题,请参考以下文章
《机器学习实战》代码实现学习一 使用K-近邻算法改进约会网站的配对效果(数据准备)