代碼來自《機器學習實戰》https://github.com/wzy6642/Machine-Learning-in-Action-Python3git
簡單地說,k-近鄰算法採用測量不一樣特徵值之間的距離方法進行分類。github
優勢:精度高、對異常值不敏感,無數據輸入假定。算法
缺點:計算複雜度高、空間複雜度高,沒法給出數據的內在含義。app
使用數據範圍:數值型、標稱型。機器學習
分類函數的僞代碼:ide
對未知類別屬性的數據集中的每一個點依次執行如下操做:函數
(1)計算已知類別數據集中的點與當前點之間的距離;學習
(2)按照距離遞增次序排序;測試
(3)選取與當前點距離最小的k個點;spa
(4)肯定前k個點所在類別的出現機率;
(5)返回前k個點出現頻率最高的類別做爲當前點的預測分類。
1 """建立數據集 2 返回: group - 數據集 3 labels - 分類標籤 4 """ 5 def createDataSet(): 6 # 四組二維特徵 7 group = np.array([[1, 101], [5, 89], [108, 5], [115, 8]]) 8 # 四組特徵的標籤 9 labels = ['愛情片', '愛情片', '動做片', '動做片'] 10 return group, labels 11 12 13 """ 14 KNN算法,分類器 15 參數: 16 inX - 用於分類的數據(測試集) 17 dataSet - 用於訓練的數據(訓練集)(n*1維列向量) 18 labels - 分類標準(n*1維列向量) 19 k - KNN算法參數,選擇距離最小的k個點 20 返回: 21 sortedClasscount[0][0] - 分類結果 22 """ 23 def classify0(inX, dataSet, labels, k): 24 # numpy函數shape[0]返回dataSet的行數(維度) 25 dataSetSize = dataSet.shape[0] 26 # 將inX重複dataSetSize次並排成一列 27 diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet 28 # 二維特徵相減後平方 29 sqDiffMat = diffMat**2 30 # sum()全部元素相加,sum(0)列相加,sum(1)行相加 31 sqDistances = sqDiffMat.sum(axis=1) 32 # 開方,計算出距離 33 distances = sqDistances**0.5 34 # argsort函數返回的是distances值從小到大的索引值 35 sortedDistIndicies = distances.argsort() 36 # 定義一個記錄類別次數的詞典 37 classCount = {} 38 # 選擇距離最小的k個點 39 for i in range(k): 40 # 取出前k個元素的類別 41 voteIlabel = labels[sortedDistIndicies[i]] 42 # 字典的get()方法,返回指定鍵的值,若是值不在字典中返回0 43 # 計算類別次數 44 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 45 # reverse降序排序字典,operator.itemgetter(1)按值排序,(0)按鍵排序 46 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) 47 # 返回次數最多的類別,即所要分類的類別 48 return sortedClassCount[0][0] 49 50 # 測試 51 group, labels = createDataSet() 52 classify0([0,0], group, labels, 3) # output: '愛情片'
這裏只能識別數字0到9,圖像爲32*32像素的黑白圖像,將圖像轉換爲文本格式。
將圖像格式化處理爲一個向量,把32*32的二進制圖像矩陣爲1*2014的向量。
1 """ 2 將32*32的二進制圖像轉換爲1*1024向量 3 參數: 4 filename - 文件名 5 返回: 6 returnVect - 返回二進制圖像的1*1024向量 7 """ 8 9 def img2vector(filename): 10 returnVect = np.zeros((1, 1024)) 11 fr = open(filename) 12 # 按行讀取 13 for i in range(32): 14 # 讀取一行數據 15 lineStr = fr.readline() 16 # 每一行的前32個數據依次存儲到returnVect中 17 for j in range(32): 18 returnVect[0, 32*i+j] = int(lineStr[j]) 19 # 返回轉換後的1*1024向量 20 return returnVect 21 22 # 測試 23 testVector = img2vector('testDigits/0_13.txt') 24 testVector[0, 0:31] 25 # output: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 26 # 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
測試算法
1 """ 2 手寫數字分類測試 3 參數: 4 None 5 返回: 6 None 7 """ 8 def handwritingClassTest(): 9 # 測試集的labels 10 hwLabels = [] 11 # 返回trainingDigits目錄下的文件名 12 trainingFilesList = listdir('trainingDigits') 13 # 返回文件夾下文件的個數 14 m = len(trainingFilesList) 15 # 初始化訓練的Mat矩陣(全零針),測試集 16 trainingMat = np.zeros((m, 1024)) 17 # 從文件名中解析出訓練集的類別 18 for i in range(m): 19 # 得到文件的名字 20 fileNameStr = trainingFilesList[i] 21 # 得到分類的數字 22 classNumber = int(fileNameStr.split('_')[0]) 23 # 將得到的類別添加到hwLabels中 24 hwLabels.append(classNumber) 25 # 將每一個文件的1*1024數據存儲到trainingMat矩陣中 26 trainingMat[i, :] = img2vector('trainingDigits/%s' % (fileNameStr)) 27 # 構造KNN分類器 28 neigh = KNN(n_neighbors=3, algorithm='auto') 29 # 擬合模型,trainingMat爲測試矩陣,hwLabels爲對應標籤 30 neigh.fit(trainingMat, hwLabels) 31 # 返回testDigits目錄下的文件列表 32 testFileList = listdir('testDigits') 33 # 錯誤檢測計數 34 errorCount =0.0 35 # 測試數據的數量 36 mTest = len(testFileList) 37 # 從文件中解析出測試集的類別並進行分類測試 38 for i in range(mTest): 39 # 得到文件名字 40 fileNameStr = testFileList[i] 41 # 得到分類的數字 42 classNumber = int(fileNameStr.split('_')[0]) 43 # 得到測試集的1*1024向量,用於訓練 44 vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr)) 45 # 得到預測結果 46 classifierResult = neigh.predict(vectorUnderTest) 47 print("分類返回結果爲%d\t真實結果爲%d" % (classifierResult, classNumber)) 48 if(classifierResult != classNumber): 49 errorCount += 1.0 50 print("總共錯了%d個數據\n錯誤率爲%f%%" % (errorCount, errorCount/mTest * 100))