【機器學習筆記】基於k-近鄰演算法的數字識別
阿新 • • 發佈:2018-12-17
更多詳細內容參考《機器學習實戰》
k-近鄰演算法簡介
簡單的說,k-近鄰演算法採用測量不同特徵值之間的距離方法進行分類。它的工作原理是:存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每個資料與所屬分類的對應關係。輸入沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較,然後演算法提取樣本集中特徵最相似(最近鄰)資料的分類標籤。一般來說,我們只選擇樣本資料集中前k個最相似的資料,這就是k-近鄰演算法中k的出處,通常k是不大於20的整數。最後選擇k個相似資料中出現次數最多的分類,作為新資料的分類。
k-近鄰演算法的一般流程
- 收集資料
- 準備資料
- 分析資料
- 訓練演算法(此步驟不適用與k-近鄰演算法)
- 測試演算法
- 使用演算法
k-近鄰演算法的的虛擬碼
對未知類別屬性的資料集中的每個點依次進行以下操作:
- 計算已知類別資料集中的點與當前點之間的距離
- 按距離遞增次序排列按距離遞增次序排列
- 選取與當前點距離最小的k個點
- 確定前k個點所在類別的出現頻率
- 返回前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變成列表