【是什么】
KNN 即 k_近鄰演算法(k- nearest neighbor) ,就是尋找K個鄰居作為該樣本的特征,近朱者赤,近墨者黑,你的鄰居是什么特征,那么就認為你也具備該特征;核心公式為:

資料來源:https://github.com/apachecn/AiLearning/blob/master/data/2.KNN/datingTestSet2.txt
讀取資料轉換成矩陣
# 提取檔案中的資料 轉換成矩陣def file2matric(filename): """ disc: param: filename: 匯入資料文本 return: 資料矩陣 """ f = open(filename,'r',encoding= 'utf-8') # 獲取檔案的行數 lines_list = f.readlines() num_of_lines = len(lines_list) # 創建存放標簽的串列 class_label_list = [] # 生成對應的空矩陣 zeros(2,3) 就是生成2行3列的0矩陣 returnMat = np.zeros((num_of_lines,3)) # 將文本中的資料放到矩陣中 for i in range(num_of_lines): lines = lines_list[i].strip().split('\t') # 將文本中的前3個資料放到矩陣中 returnMat[i,:] = lines[0:3] # 將標簽存到串列中 class_label_list.append(int(lines[-1])) # print(returnMat) return returnMat, class_label_list
利用 matplotlib 繪制散點圖
def DrawScatter(dataMat,label_list): # 匯入中文字體,及字體大小 zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=14) # 繪制繪圖視窗 2行2列 fig,ax = plt.subplots(2,2,figsize=(13,8)) # 不同標簽賦予不同顏色 label_color = [] for i in label_list: if i == 1: label_color.append('black') elif i == 2: label_color.append('orange') elif i == 3: label_color.append('red') # 開始繪制散點圖 設定散點尺寸與透明度 scatter_size = 12 scatter_alpha = 0.5 # ===================散點圖======================== ax[0][0].scatter(dataMat[:,0], dataMat[:,1],color = label_color,s = scatter_size ,alpha = scatter_alpha) ax[0][1].scatter(dataMat[:, 1], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha) ax[1][0].scatter(dataMat[:, 0], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha) # 坐標軸標題 title_list = ['每年獲得的飛行常客里程數和玩視頻游戲所消耗時間占比', '每年獲得的飛行常客里程數和每周消費的冰激淋公升數', '玩視頻游戲所消耗時間占比和每周消費的冰激淋公升數'] x_name_list = ['每年獲得的飛行常客里程數','玩視頻游戲所消耗時間占比','每周消費的冰激淋公升數'] y_name_list = ['玩視頻游戲所消耗時間占比','每周消費的冰激淋公升數','每年獲得的飛行常客里程數'] #設定圖例 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') p = 0 for i in range(2): for j in range(2): if p > 2: break # 設定坐標軸名稱和標題 plt.setp(ax[i][j].set_title(u'%s'%(title_list[p]),FontProperties = zhfont),size=9, weight='bold', color='red') plt.setp(ax[i][j].set_xlabel(u'%s'%(x_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black') plt.setp(ax[i][j].set_ylabel(u'%s'%(y_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black') p+=1 # 添加圖例 ax[0][0].legend(handles=[didntLike, smallDoses, largeDoses]) ax[0][1].legend(handles=[didntLike, smallDoses, largeDoses]) ax[1][0].legend(handles=[didntLike, smallDoses, largeDoses]) plt.show()

對資料進行歸一化處理
由于不同資料的范圍波動不同,在權重一樣的情況下,需要進行歸一化,即將資料轉換成0-1之間
# 對矩陣進行歸一化處理def dataNorm(dataMat): """ :param dataMat: :return: 歸一化后的資料集 歸一化公式: Y = (X - Xmin)/(Xmax - Xmin) """ # max(0) min(0) 求出每列的最大值和最小值 d_min = dataMat.min(0) d_max = dataMat.max(0) # 計算極差 d_ranges = d_max - d_min # 創建輸出矩陣 normDataSet = np.zeros(np.shape(dataMat)) print(normDataSet) # 獲得矩陣行數 .shape 獲取矩陣的大小 3x3 m = dataMat.shape[0] # 計算 (X - Xmin) 這部分 首先要創建Xmin矩陣 將d_min擴展到m行 # 需要使用np.tile 函式進行擴展 將d_min擴展成m行1列 變成m x 3 矩陣 normDataSet = dataMat - np.tile(d_min,(m,1)) print(normDataSet) # 計算Y normDataSet = normDataSet / np.tile(d_ranges,(m,1)) print(normDataSet) return normDataSet
創建分類函式與分類器(kNN演算法的實作)
(ps:每次都需要將測驗資料與所有訓練資料進行對比,感覺比較繁瑣)
def classfy_fun(test_data, train_data, labels, k): """ :param test_data: 測驗集 :param train_data: 訓練集 :param labels: 訓練集標簽 :param k: KNN 演算法引數 選擇距離最小的個數 :return: 分類結果 """ # 計算訓練集的矩陣行數 train_size = train_data.shape[0] # 接下來按照歐氏距離進行元素距離計算 公式 # 將測驗集擴充成與訓練集相同行數 求差 diffMat = np.tile(test_data,(train_size,1)) - train_data # 將差值矩陣的每個元素平方 sq_diffMat = diffMat**2 # 差值平方矩陣每行元素相加 axis = 1 是按行相加 sum_diffMat = sq_diffMat.sum(axis = 1) # 對新的求和矩陣進行開方 得到距離值 distances = sum_diffMat ** 0.5 # 獲得距離值中從小到大值的索引 sorted_distant = distances.argsort() # 定義一個字典 存放標簽 與 出現的數量 class_count = {} for i in range(k): # 找出前k個距離值最小的對應標簽 temp_label = labels[sorted_distant[i]] # 將標簽作為 key 存放到字典中 出現次數作為 value class_count[temp_label] = class_count.get(temp_label,0) + 1 # 將字典按照value 大小進行排序 sort_class_count = sorted(class_count.items(),key = operator.itemgetter(1)) return sort_class_count[0][0] pass# 創建分類器函式def dating_class_test(): # 首先獲取檔案,將檔案分成測驗集和訓練集 dating_Mat, dating_label = file2matric('datingdata.txt') # 設定測驗集的比例 test_ratio = 0.1 # 資料歸一化 normMat = dataNorm(dating_Mat) #獲得矩陣的行數 m = normMat.shape[0] # 計算測驗集的數量 numTestData = https://www.cnblogs.com/wangxiaobei2019/p/int(m * test_ratio) # 錯誤分類的數量 error_count = 0.0 for i in range(numTestData): class_result = classfy_fun(dating_Mat[i,:], dating_Mat[numTestData:m,:], dating_label[numTestData:m],4 ) print("分類結果:%s,實際分類:%s"%(class_result,dating_label[i])) if class_result != dating_label[i]: error_count += 1 # print("錯誤識別的數量:%f" %error_count) print("正確率:%f%% \n" %((1 - error_count / numTestData)*100))

從結果看 識別率還是很低的,目前k值為4 ,可以改變k值看看正確率的變化
完整代碼

1 #!/usr/bin/python 2 # -*- coding: UTF-8 -*- 3 """ 4 【KNN 實戰】 5 6 """ 7 import numpy as np 8 import matplotlib.pyplot as plt 9 import matplotlib.lines as mlines 10 from matplotlib.font_manager import FontProperties 11 import operator 12 13 # 提取檔案中的資料 轉換成矩陣 14 def file2matric(filename): 15 """ 16 disc: 17 param: filename: 匯入資料文本 18 return: 資料矩陣 19 """ 20 f = open(filename,'r',encoding= 'utf-8') 21 # 獲取檔案的行數 22 lines_list = f.readlines() 23 num_of_lines = len(lines_list) 24 # 創建存放標簽的串列 25 class_label_list = [] 26 # 生成對應的空矩陣 zeros(2,3) 就是生成2行3列的0矩陣 27 returnMat = np.zeros((num_of_lines,3)) 28 # 將文本中的資料放到矩陣中 29 for i in range(num_of_lines): 30 lines = lines_list[i].strip().split('\t') 31 # 將文本中的前3個資料放到矩陣中 32 returnMat[i,:] = lines[0:3] 33 # 將標簽存到串列中 34 class_label_list.append(int(lines[-1])) 35 36 # print(returnMat) 37 return returnMat, class_label_list 38 39 def DrawScatter(dataMat,label_list): 40 # 匯入中文字體,及字體大小 41 zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=14) 42 # 繪制繪圖視窗 2行2列 43 fig,ax = plt.subplots(2,2,figsize=(13,8)) 44 # 不同標簽賦予不同顏色 45 label_color = [] 46 for i in label_list: 47 if i == 1: 48 label_color.append('black') 49 elif i == 2: 50 label_color.append('orange') 51 elif i == 3: 52 label_color.append('red') 53 # 開始繪制散點圖 設定散點尺寸與透明度 54 scatter_size = 12 55 scatter_alpha = 0.5 56 # ===================散點圖======================== 57 ax[0][0].scatter(dataMat[:,0], dataMat[:,1],color = label_color,s = scatter_size ,alpha = scatter_alpha) 58 ax[0][1].scatter(dataMat[:, 1], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha) 59 ax[1][0].scatter(dataMat[:, 0], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha) 60 61 # 坐標軸標題 62 title_list = ['每年獲得的飛行常客里程數和玩視頻游戲所消耗時間占比', 63 '每年獲得的飛行常客里程數和每周消費的冰激淋公升數', 64 '玩視頻游戲所消耗時間占比和每周消費的冰激淋公升數'] 65 x_name_list = ['每年獲得的飛行常客里程數','玩視頻游戲所消耗時間占比','每周消費的冰激淋公升數'] 66 y_name_list = ['玩視頻游戲所消耗時間占比','每周消費的冰激淋公升數','每年獲得的飛行常客里程數'] 67 #設定圖例 68 didntLike = mlines.Line2D([], [], color='black', marker='.', 69 markersize=6, label='didntLike') 70 smallDoses = mlines.Line2D([], [], color='orange', marker='.', 71 markersize=6, label='smallDoses') 72 largeDoses = mlines.Line2D([], [], color='red', marker='.', 73 markersize=6, label='largeDoses') 74 75 p = 0 76 for i in range(2): 77 for j in range(2): 78 if p > 2: 79 break 80 # 設定坐標軸名稱和標題 81 plt.setp(ax[i][j].set_title(u'%s'%(title_list[p]),FontProperties = zhfont),size=9, weight='bold', color='red') 82 plt.setp(ax[i][j].set_xlabel(u'%s'%(x_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black') 83 plt.setp(ax[i][j].set_ylabel(u'%s'%(y_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black') 84 p+=1 85 # 添加圖例 86 ax[0][0].legend(handles=[didntLike, smallDoses, largeDoses]) 87 ax[0][1].legend(handles=[didntLike, smallDoses, largeDoses]) 88 ax[1][0].legend(handles=[didntLike, smallDoses, largeDoses]) 89 plt.savefig('.\\123.png', bbox_inches='tight') 90 plt.show() 91 92 # 對矩陣進行歸一化處理 93 def dataNorm(dataMat): 94 """ 95 :param dataMat: 96 :return: 歸一化后的資料集 97 歸一化公式: Y = (X - Xmin)/(Xmax - Xmin) 98 """ 99 # max(0) min(0) 求出每列的最大值和最小值100 d_min = dataMat.min(0)101 d_max = dataMat.max(0)102 # 計算極差103 d_ranges = d_max - d_min104 # 創建輸出矩陣105 normDataSet = np.zeros(np.shape(dataMat))106 print(normDataSet)107 # 獲得矩陣行數 .shape 獲取矩陣的大小 3x3108 m = dataMat.shape[0]109 # 計算 (X - Xmin) 這部分 首先要創建Xmin矩陣 將d_min擴展到m行110 # 需要使用np.tile 函式進行擴展 將d_min擴展成m行1列 變成m x 3 矩陣111 normDataSet = dataMat - np.tile(d_min,(m,1))112 print(normDataSet)113 # 計算Y114 normDataSet = normDataSet / np.tile(d_ranges,(m,1))115 116 print(normDataSet)117 return normDataSet118 119 def classfy_fun(test_data, train_data, labels, k):120 """121 122 :param test_data: 測驗集123 :param train_data: 訓練集124 :param labels: 訓練集標簽125 :param k: KNN 演算法引數 選擇距離最小的個數126 :return: 分類結果127 """128 # 計算訓練集的矩陣行數129 train_size = train_data.shape[0]130 # 接下來按照歐氏距離進行元素距離計算 公式131 # 將測驗集擴充成與訓練集相同行數 求差132 diffMat = np.tile(test_data,(train_size,1)) - train_data133 # 將差值矩陣的每個元素平方134 sq_diffMat = diffMat**2135 # 差值平方矩陣每行元素相加 axis = 1 是按行相加136 sum_diffMat = sq_diffMat.sum(axis = 1)137 # 對新的求和矩陣進行開方 得到距離值138 distances = sum_diffMat ** 0.5139 # 獲得距離值中從小到大值的索引140 sorted_distant = distances.argsort()141 # 定義一個字典 存放標簽 與 出現的數量142 class_count = {}143 for i in range(k):144 # 找出前k個距離值最小的對應標簽145 temp_label = labels[sorted_distant[i]]146 # 將標簽作為 key 存放到字典中 出現次數作為 value147 class_count[temp_label] = class_count.get(temp_label,0) + 1148 # 將字典按照value 大小進行排序149 sort_class_count = sorted(class_count.items(),key = operator.itemgetter(1))150 return sort_class_count[0][0]151 pass152 # 創建分類器函式153 def dating_class_test():154 155 # 首先獲取檔案,將檔案分成測驗集和訓練集156 dating_Mat, dating_label = file2matric('datingdata.txt')157 # 設定測驗集的比例158 test_ratio = 0.1159 # 資料歸一化160 normMat = dataNorm(dating_Mat)161 #獲得矩陣的行數162 m = normMat.shape[0]163 # 計算測驗集的數量164 numTestData = https://www.cnblogs.com/wangxiaobei2019/p/int(m * test_ratio)165 # 錯誤分類的數量166 error_count = 0.0167 168 for i in range(numTestData):169 class_result = classfy_fun(dating_Mat[i,:], dating_Mat[numTestData:m,:],170 dating_label[numTestData:m],4 )171 print("分類結果:%s,實際分類:%s"%(class_result,dating_label[i]))172 if class_result != dating_label[i]:173 error_count += 1174 # print("錯誤識別的數量:%f" %error_count)175 print("正確率:%f%% \n" %((1 - error_count / numTestData)*100))176 177 def main():178 # reMat, label = file2matric('datingdata.txt')179 # DrawScatter(reMat,label )180 # dataNorm(reMat)181 # 測驗分類情況182 dating_class_test()183 pass184 185 186 if __name__ =='__main__':187 main()View Code
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/73659.html
標籤:其他
上一篇:CornerNet: Detecting Objects as Paired Keypoints
下一篇:如何免費使用GPU跑深度學習代碼

