手寫識別系統(tǒng)
我們一步一步地構(gòu)造使用k-近鄰分類器的手寫識別系統(tǒng)。為了簡單起見,這里對數(shù)據(jù)有以下要求
- 數(shù)字只能識別0到9
- 需要識別的數(shù)字已經(jīng)使用圖形處理軟件處理過,處理成具有相同的色彩和大小,寬和高是32像素×32像素的黑白圖像
- 將圖像轉(zhuǎn)換成文本進(jìn)行處理
機(jī)器學(xué)習(xí)的六大步驟
- 收集數(shù)據(jù):
- 準(zhǔn)備數(shù)據(jù):編程將圖像格式轉(zhuǎn)化為分類器使用的向量格式
- 分析數(shù)據(jù):
- 訓(xùn)練算法:(此步驟不適用于k-近鄰算法)
- 測試算法:編程將提供的部分?jǐn)?shù)據(jù)集作為測試樣本,測試樣本與非測試樣本的區(qū)別就在于測試樣本是已經(jīng)完成分類的數(shù)據(jù)。
- 使用算法:
準(zhǔn)備數(shù)據(jù):將圖像轉(zhuǎn)化為測試向量
- 在文件trainingDigits中包含了大約2000個例子,每個數(shù)字大概有200個樣本
- 在文件testDigits中包含了大約900個測試用例。
然后我們使用trainingDigits中的數(shù)據(jù)進(jìn)行訓(xùn)練,使用testDigits中的數(shù)據(jù)進(jìn)行測試。
我們將繼續(xù)使用前面約會網(wǎng)站所使用的分類器,所以我們要將圖像格式處理為一個向量,將32×32的矩陣轉(zhuǎn)化為1×1024的向量。
# 將32*32的數(shù)據(jù)轉(zhuǎn)化為1*1024的數(shù)據(jù)
def imgToVector(filaname):
returnVector = zeros((1,1024))
fr = open(filaname)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVector[32*i+j] = int(lineStr[j]) # 保留疑問
return returnVector
測試算法:使用k-近鄰算法識別手寫數(shù)字
def handWritingClassTest():
hwLables = []
trainingFileList = listdir('trainingDigits') # os模塊下的listdir可以取出該目錄下的所有文件名,返回一個list
m = len(trainingFileList) # 該目錄下的文件的數(shù)量
trainingMat = zeros((m, 1024))
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] # 去掉后綴
classNumStr = int(fileStr.split('_')[0]) # 提取標(biāo)簽
hwLables.append(classNumStr)
trainingMat[i, :] = imgToVector('trainingDigits/%s' % fileNameStr) # 調(diào)用格式轉(zhuǎn)換函數(shù)
testFileList = listdir('testDigits')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] # 去掉后綴
classNumStr = int(fileStr.split('_')[0]) # 提取標(biāo)簽
vectorUnderTest = imgToVector('testDigits/%s' % fileNameStr)
classFierResult = classify(vectorUnderTest, trainingMat, hwLables, 3)
print("分類器返回的結(jié)果為:%d, 實(shí)際情況為:%d" % (classFierResult, classNumStr))
if (classFierResult != classNumStr): errorCount += 1.0
print("錯誤率為:%f" % (errorCount / float(mTest)))
完整代碼和數(shù)據(jù)見:https://github.com/IBITM/Machine-Learning-in-Action/tree/master/kNN
kNN算法小結(jié)
- k-近鄰算法是分類數(shù)據(jù)最簡單最有效的算法,它是基于實(shí)例的學(xué)習(xí),當(dāng)我們使用算法時必須有接近實(shí)際數(shù)據(jù)的訓(xùn)練樣本數(shù)據(jù)。
- k-近鄰算法必須保存全部的數(shù)據(jù)集,如果訓(xùn)練的數(shù)據(jù)集很大,我們必須耗費(fèi)大量的存儲空間。此外,因?yàn)楸仨殞?shù)據(jù)集中的每個數(shù)據(jù)計(jì)算距離值,使用時可能非常耗費(fèi)時間。
- k-鄰近算法的另一個很重大的缺陷是無法給出任何數(shù)據(jù)的基礎(chǔ)結(jié)構(gòu)信息,我們無法知道我們所操作的樣本具有什么樣子的特征。接下來我們要學(xué)習(xí)使用概率測量的方法處理分類問題,聽說這個算法可以解決這個問題。