手寫識別系統
說明:
將數據集文件 ‘digits.zip’ 解壓至當前文件夾
定義將圖像轉換爲向量函數
# 導入程序所需要的模塊
import numpy as np
import operator
from os import listdir
# 將32*32的二進制圖像矩陣轉換爲1*1024向量
def img2vector(filename):
# 存儲圖片像素的向量維度是1x1024
# 創建1*1024零向量
returnVect = np.zeros((1, 1024))
# 打開文件
fr = open(filename)
# 按行讀取
for i in range(32):
# .readline() 和 .readlines() 之間的差異是後者一次讀取整個文件
# .readline() 每次只讀取一行
lineStr = fr.readline()
#每一行的前32個元素依次添加到returnVect中
for j in range(32):
returnVect[0, 32*i+j] = int(lineStr[j])
# 返回轉換後的1*1024向量
return returnVect
#測試img2vector函數,然後與文本編輯器打開的文件進行比較。
returnVect=img2vector("./digits/trainingDigits/0_0.txt")
returnVect[0,0:31]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
定義 k 近鄰算法
def classify0(inX, dataSet, labels, k): # inX是測試集,dataSet是訓練集,lebels是訓練樣本標籤,k是取的最近鄰個數
dataSetSize = dataSet.shape[0] # 訓練樣本個數
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # np.tile: 重複n次
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5 # distance是inX與dataSet的歐氏距離
sortedDistIndicies = distances.argsort() # 返回排序從小到達的索引位置
classCount = {} # 字典存儲k近鄰不同label出現的次數
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # 對應label加1,classCount中若無此key,則默認爲0
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # operator.itemgetter 獲取對象的哪個維度的數據
return sortedClassCount[0][0] # 返回k近鄰中所屬類別最多的哪一類
定義手寫數字識別系統函數
def handwritingClassTest():
# 訓練樣本的類別標籤
hwLabels = []
#導入訓練集,函數listdir可以列出給定目錄的文件名。
trainingFileList = listdir('./digits/trainingDigits')
#返回文件夾下文件的個數
m = len(trainingFileList)
#初始化訓練矩陣
trainingMat = np.zeros((m, 1024))
#從文件名中解析出訓練集的類別
for i in range(m):
#fileNameStr得到的是每個文件名稱,例如"0_0.txt"
fileNameStr = trainingFileList[i]
#去掉“.txt”,剩下“0_0”
fileStr = fileNameStr.split('.')[0]
# 按下劃線‘_' 劃分“0_0”,取第一個元素爲類別標籤
classNumStr = int(fileStr.split('_')[0])
#將獲得的類別添加到 hwLabels中
hwLabels.append(classNumStr)
#將每一個文件的1x1024數據存儲到trainingMat矩陣中
trainingMat[i, :] = img2vector('./digits/trainingDigits/%s' % fileNameStr)
# 測試樣本
#導入測試集,函數listdir可以列出給定目錄的文件名。
testFileList = listdir('./digits/testDigits') #iterate through the test set
#錯誤檢測計數,初始爲0
errorCount = 0.0
#測試數據的數量
mTest = len(testFileList)
for i in range(mTest):
# fileNameStr 得到的是每個文件名稱,例如"0_0.txt"
fileNameStr = testFileList[i]
#去掉“.txt”,剩下“0_0”
fileStr = fileNameStr.split('.')[0]
# 按下劃線‘_' 劃分“0_0”,取第一個元素爲類別標籤
classNumStr = int(fileStr.split('_')[0])
#獲得測試集的1x1024向量
vectorUnderTest = img2vector('./digits/testDigits/%s' % fileNameStr)
# 調用knn函數
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 1)
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr):
errorCount += 1.0
print("\nthe total number of errors is: %d" % errorCount)
print("\nthe total error rate is: %f" % (errorCount/float(mTest)))
handwritingClassTest()
參考文檔: