目的:利用kNN識別數字0-9
材料:32*32的數字方陣(保存形式是文本文件)
#-*-coding:utf-8-*- from numpy import * def img2vector(filename): #生成一個1*1024的array(zeros是numpy的函數,至於array與list區別這里就不多介紹了) returnVect = zeros((1,1024)) #使用open函數打開一個文本文件 fr = open(filename) #循環讀取文件內容 for i in range(32): #讀取一行,返回字符串 linestr = fr.readline() for j in range(32): #讀取字符串0 或者 1 returnVect[0,32*i+j] = int(linestr[j]) #返回這個array return returnVect
這個程序很清晰,不做什么解釋了。再看一下分類器是怎么實現的:
#定義測試代碼 def handwringClassTest(): #定義一個list,用於記錄分類 hwLabels = [] #前面的Python os.listdir 可以列出 dir 里面的所有文件和目錄,但不包括子目錄中的內容。 #os.walk 可以遍歷下面的所有目錄,包括子目錄。 trainingFileList = listdir('trainingDigits') #求出文件的長度 m = len(trainningFileList) #生成m*1024的array,每個文件分配1024個0 trainingMat = zeros((m,1024)) #循環,對每一個file for i in range(m): #當前文件 fileNameStr = trainingFileList[i] #理解這段代碼要知道文件的命名方式,這里是這樣命名的9_45.txt,9表示分類,45表示第45個。 fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) hwLabels.append(classNumStr) #調用img2vector,將原文件寫入trainingMat trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr) #找到testDigits中的文件 testFileList = listdir('testDigits') #計算誤差 errorCount = 0.0 #多少個文件 mTest = len(testFileList) #遍歷test文件 for i inrange(mTest): #test文件 fileNameStr = testFileList[i] #分類 fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) #轉換成1*1024 vectorUnderTest = img2vector('testDigits/%s' % fileNameStr) # 調用knn分類 classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) #輸出 print "the classifier came back with:%d, the real anwer is : %d" % (classifierResult, classNumStr) #計算誤差 if (classifierResult != classNumStr): errorCount += 1.0 print "\n the total numbe of error is: %d" % errorCount print "\nthe total error rate is: %f" % (errorCount/flaot(mTest))
總結
kNN是一種最簡單最有效的算法。但是kNN必須保留所有的數據集,如果訓練數據集的很大,必須使用大量的存儲空間,此外,需要對每一個數據計算距離,非常耗時。另外,它無法給出任何數據的基礎結構信息(目前我還不能理解這句話,待更新。。。)。