1. 程式人生 > >【機器學習筆記】基於k-近鄰演算法的數字識別

【機器學習筆記】基於k-近鄰演算法的數字識別

更多詳細內容參考《機器學習實戰》

k-近鄰演算法簡介

簡單的說,k-近鄰演算法採用測量不同特徵值之間的距離方法進行分類。它的工作原理是:存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每個資料與所屬分類的對應關係。輸入沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較,然後演算法提取樣本集中特徵最相似(最近鄰)資料的分類標籤。一般來說,我們只選擇樣本資料集中前k個最相似的資料,這就是k-近鄰演算法中k的出處,通常k是不大於20的整數。最後選擇k個相似資料中出現次數最多的分類,作為新資料的分類。

k-近鄰演算法的一般流程

  1. 收集資料
  2. 準備資料
  3. 分析資料
  4. 訓練演算法(此步驟不適用與k-近鄰演算法)
  5. 測試演算法
  6. 使用演算法

k-近鄰演算法的的虛擬碼

對未知類別屬性的資料集中的每個點依次進行以下操作:

  1. 計算已知類別資料集中的點與當前點之間的距離
  2. 按距離遞增次序排列按距離遞增次序排列
  3. 選取與當前點距離最小的k個點
  4. 確定前k個點所在類別的出現頻率
  5. 返回前k個點出現頻率最高的類別作為當前點的預測分類

示例

示例為kaggle上的’Digit Recognizer’,實現數字識別 具體的題目描述和資料集下載可以點選連結Digit Recognizer

程式碼

from numpy import *
import operator
import
csv def getTrainData(): #獲取訓練集的資料 with open('D:\\學習\\kaggle\\Digit Recoginzer\\train.csv') as f: traindata=[] datafirst=csv.reader(f) #讀取csv檔案 for row in datafirst: #訓練資料放入列表中 traindata.append(row) traindata.pop(
0) #去除第一行文字說明 trainlabel=[] #取出訓練標籤 for i in traindata: trainlabel.append(int(i[0])) i.pop(0) for i in range(len(traindata)): #把列表中字元型別變成整數型別 for j in range(len(traindata[0])): #同時便於計算,把非零常數改為1 if traindata[i][j]!='0': traindata[i][j]=1 else: traindata[i][j]=int(traindata[i][j]) return array(traindata),array(trainlabel) def getTestData(): #獲取測試集資料 with open('D:\\學習\\kaggle\\Digit Recoginzer\\test.csv') as f: testdata=[] datafirst=csv.reader(f) for row in datafirst: testdata.append(row) testdata.pop(0) for i in range(len(testdata)): for j in range(len(testdata[0])): if testdata[i][j]!='0': testdata[i][j]=1 else: testdata[i][j]=int(testdata[i][j]) return array(testdata) def classify0(inX,dataSet,labels,k): #inX是一個待分類的測試向量 dataSetSize=dataSet.shape[0] #取出dataSet的行數 #tile把inX整體在行上重複dataSetSize次,列上重複1次(下面程式碼中) 具體可以自己試一下 diffMat=tile(inX,(dataSetSize,1))-dataSet #測試向量與每個訓練向量的各分量差 sqDiffMat=diffMat**2 sqDistances=sqDiffMat.sum(axis=1) #測試向量與每個訓練向量的的分量的平方和 distances=sqDistances**0.5 #開方後即歐式距離 sortedDistIndicies=distances.argsort() #返回距離從小到大的索引值 classCount={} for i in range(k): voteIlabel=labels[sortedDistIndicies[i]] classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #累加距離排名前k箇中每個標籤出現的次數 #把classCount中按標籤的出現次數排序 sortedclassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) return sortedclassCount[0][0] traindata,trainlabel=getTrainData() testdata=getTestData() testlabel=[] for i in testdata: testlabel.append(classify0(i,traindata,trainlabel,5)) testlabel1=[[i]for i in testlabel] with open('testlabel.csv','w',newline='') as f: #開啟當前路徑下的檔案 fwriter=csv.writer(f) #返回writer物件 fwriter.writerows(testlabel1) #一行行寫入,每行必須是可迭代的物件,所以要把label中每一個int變成列表