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