机器学习实战笔记——KNN约会网站

  1 '''
  2     机器学习实战——KNN约会网站优化
  3 '''
  4 
  5 import operator
  6 import numpy as np
  7 from numpy import *
  8 from matplotlib.font_manager import  FontProperties
  9 import matplotlib.lines as mlines
 10 import matplotlib.pyplot as plt
 11 
 12 # largeDoses :极具魅力 ;smallDoses :魅力一般 ;didntLike:不喜欢
 13 def str_3(str_i):
 14     if str_i=='largeDoses':
 15         return 3
 16     elif str_i=='smallDoses':
 17         return 2
 18     elif str_i=='didntLike':
 19         return 1
 20     else:
 21         return np.nan
 22 
 23 # 获取特征矩阵、label向量
 24 def file2matrix(filename):
 25     fr = open(filename,'r') #打开文件
 26     numberOfLines = len(fr.readlines())         # 获得文件的行数
 27     returnMat = zeros((numberOfLines,3))        # 创建一个空的特征矩阵
 28     classLabelVector = []                       # 分类label向量
 29     fr = open(filename,'r')
 30     index = 0 #行索引
 31     for line in fr.readlines():
 32         line = line.strip() # 为空是默认删除('\n','\r','\t',' ')
 33         listFromLine = line.split('\t') #读取的每行数据根据'\t'进行切片
 34         returnMat[index,:] = listFromLine[0:3] #提取对应行的前三行(特征列)存放入retunMat特征矩阵
 35         classLabelVector.append(str_3(listFromLine[-1])) #将每行的label转为数值后存入classLabelVector
 36         index += 1
 37     # 返回特征矩阵和分类label向量
 38     return returnMat,classLabelVector
 39 
 40 # 归一化
 41 def autoNorm(dataSet):
 42     #获得数据的最小值 按列寻找最大|最小值
 43     minVals = dataSet.min(0)
 44     maxVals = dataSet.max(0)
 45     # print('minVals:\n',minVals)
 46     # print('maxVals:\n',maxVals)
 47     #最大值和最小值的范围
 48     ranges = maxVals - minVals
 49     #shape(dataSet)返回dataSet的矩阵行列数
 50     normDataSet = np.zeros(np.shape(dataSet))
 51     #返回dataSet的行数
 52     m = dataSet.shape[0]
 53     #原始值减去最小值
 54     normDataSet = dataSet - np.tile(minVals, (m, 1))
 55     #除以最大和最小值的差,得到归一化数据
 56     normDataSet = normDataSet / np.tile(ranges, (m, 1))
 57     #返回归一化数据结果,数据范围,最小值
 58     return normDataSet, ranges, minVals
 59 
 60 # 画图
 61 def showdatas(datingDataMat, datingLabels):
 62     #设置汉字格式
 63     font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
 64     #将fig画布分隔成1行1列,不共享x轴和y轴,fig画布的大小为(13,8)
 65     #当nrow=2,nclos=2时,代表fig画布被分为四个区域,axs[0][0]表示第一行第一个区域
 66     fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(13,8))
 67 
 68     numberOfLabels = len(datingLabels)
 69     LabelsColors = []
 70     for i in datingLabels:
 71         if i == 1:
 72             LabelsColors.append('black')
 73         if i == 2:
 74             LabelsColors.append('orange')
 75         if i == 3:
 76             LabelsColors.append('red')
 77     #画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第二列(玩游戏)数据画散点数据,散点大小为15,透明度为0.5
 78     axs[0][0].scatter(x=datingDataMat[:,0], y=datingDataMat[:,1], color=LabelsColors,s=15, alpha=.5)
 79     #设置标题,x轴label,y轴label
 80     axs0_title_text = axs[0][0].set_title(u'每年获得的飞行常客里程数与玩视频游戏所消耗时间占比',FontProperties=font)
 81     axs0_xlabel_text = axs[0][0].set_xlabel(u'每年获得的飞行常客里程数',FontProperties=font)
 82     axs0_ylabel_text = axs[0][0].set_ylabel(u'玩视频游戏所消耗时间占',FontProperties=font)
 83     plt.setp(axs0_title_text, size=9, weight='bold', color='red')
 84     plt.setp(axs0_xlabel_text, size=7, weight='bold', color='black')
 85     plt.setp(axs0_ylabel_text, size=7, weight='bold', color='black')
 86 
 87     #画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5
 88     axs[0][1].scatter(x=datingDataMat[:,0], y=datingDataMat[:,2], color=LabelsColors,s=15, alpha=.5)
 89     #设置标题,x轴label,y轴label
 90     axs1_title_text = axs[0][1].set_title(u'每年获得的飞行常客里程数与每周消费的冰激淋公升数',FontProperties=font)
 91     axs1_xlabel_text = axs[0][1].set_xlabel(u'每年获得的飞行常客里程数',FontProperties=font)
 92     axs1_ylabel_text = axs[0][1].set_ylabel(u'每周消费的冰激淋公升数',FontProperties=font)
 93     plt.setp(axs1_title_text, size=9, weight='bold', color='red')
 94     plt.setp(axs1_xlabel_text, size=7, weight='bold', color='black')
 95     plt.setp(axs1_ylabel_text, size=7, weight='bold', color='black')
 96 
 97     #画出散点图,以datingDataMat矩阵的第二(玩游戏)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5
 98     axs[1][0].scatter(x=datingDataMat[:,1], y=datingDataMat[:,2], color=LabelsColors,s=15, alpha=.5)
 99     #设置标题,x轴label,y轴label
100     axs2_title_text = axs[1][0].set_title(u'玩视频游戏所消耗时间占比与每周消费的冰激淋公升数',FontProperties=font)
101     axs2_xlabel_text = axs[1][0].set_xlabel(u'玩视频游戏所消耗时间占比',FontProperties=font)
102     axs2_ylabel_text = axs[1][0].set_ylabel(u'每周消费的冰激淋公升数',FontProperties=font)
103     plt.setp(axs2_title_text, size=9, weight='bold', color='red')
104     plt.setp(axs2_xlabel_text, size=7, weight='bold', color='black')
105     plt.setp(axs2_ylabel_text, size=7, weight='bold', color='black')
106     #设置图例
107     didntLike = mlines.Line2D([], [], color='black', marker='.',
108                       markersize=6, label='didntLike')
109     smallDoses = mlines.Line2D([], [], color='orange', marker='.',
110                       markersize=6, label='smallDoses')
111     largeDoses = mlines.Line2D([], [], color='red', marker='.',
112                       markersize=6, label='largeDoses')
113     #添加图例
114     axs[0][0].legend(handles=[didntLike,smallDoses,largeDoses])
115     axs[0][1].legend(handles=[didntLike,smallDoses,largeDoses])
116     axs[1][0].legend(handles=[didntLike,smallDoses,largeDoses])
117     #显示图片
118     plt.show()
119 
120 # classify0(测试集特征,训练集特征,训练集label,4)
121 def classify0(inX, dataSet, labels, k):
122     # numpy函数shape[0]返回dataSet的行数  1000
123     dataSetSize = dataSet.shape[0]
124     # 在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)  将单个样本的维度扩展为和dataSet相同
125     diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
126     # print(diffMat.shape) # (900,3)
127     # 二维特征相减后平方
128     sqDiffMat = diffMat ** 2
129     # print(sqDiffMat.shape) # (900,3)
130     # sum()所有元素相加,sum(0)列相加,sum(1)行相加   # 样本
131     sqDistances = sqDiffMat.sum(axis=1)
132     # print(sqDistances.shape) # (900,)
133     # print(sqDistances)
134     # 开方,计算出距离
135     distances = sqDistances**0.5
136     # 以上四步为欧氏距离计算公式
137 
138     # 返回distances中元素从小到大排序后的索引值  argsort()返回数字值从小到大的索引值列表
139     sortedDistIndices = distances.argsort()
140     # 定一个记录类别次数的字典
141     classCount = {}
142     for i in range(k):
143         # 取出前k个元素的类别
144         voteIlabel = labels[sortedDistIndices[i]]
145         # dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
146         # 计算类别次数 # get(返回此键的值,default) 返回指定键的值,如果此键不存在返回0
147         classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
148     # python3中用items()替换python2中的iteritems()
149     # key=operator.itemgetter(1)根据字典的值进行排序
150     # key=operator.itemgetter(0)根据字典的键进行排序
151     # reverse降序排序字典
152     sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
153     # 返回次数最多的类别,即所要分类的类别
154     return sortedClassCount[0][0]
155 
156 
157 def datingClassTest(filename):
158     # 打开的文件名
159     filename = filename
160     # 将返回的特征矩阵和分类向量分别存储到datingDataMat和datingLabels中
161     datingDataMat, datingLabels = file2matrix(filename)
162     # 取所有数据的百分之十
163     hoRatio = 0.10
164     # 数据归一化,返回归一化后的矩阵,数据范围,数据最小值
165     normMat, ranges, minVals = autoNorm(datingDataMat)
166     # 获得normMat的行数 (特征矩阵)
167     m = normMat.shape[0]
168     # 百分之十的测试数据的个数
169     numTestVecs = int(m * hoRatio)
170     # 分类错误计数
171     errorCount = 0.0
172 
173     for i in range(numTestVecs):
174         # 前numTestVecs个数据作为测试集,后m-numTestVecs个数据作为训练集
175         classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],
176             datingLabels[numTestVecs:m], 4)
177         print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
178         if classifierResult != datingLabels[i]:
179             errorCount += 1.0
180     print("错误率:%f%%" %(errorCount/float(numTestVecs)*100))
181 
182 
183 if __name__ == '__main__':
184     filename = '../data/datingTestSet.txt'
185     # 接收返回的特征矩阵和分类label向量
186     datingDataMat, datingLabels = file2matrix(filename)
187     # print(datingDataMat,datingLabels)
188     # showdatas(datingDataMat,datingLabels) # 调用此函数以画图
189     datingClassTest(filename)

下次继续~~~

posted @ 2019-06-20 15:27  张知行  阅读(398)  评论(0编辑  收藏  举报