機器學習實戰筆記——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)

下次繼續~~~python

相關文章
相關標籤/搜索