1。總體概要
kNN算法已經(jīng)在上一篇博客中說明。對(duì)于要處理手寫體數(shù)字,需要處理的點(diǎn)主要包括:
(1)圖片的預(yù)處理:將png,jpg等格式的圖片轉(zhuǎn)換成文本數(shù)據(jù),本博客的思想是,利用圖片的rgb16進(jìn)制編碼(255,255,255)為白色,(0,0,0)為黑色,獲取圖片大小后,逐個(gè)像素進(jìn)行判斷分析,當(dāng)此像素為空白時(shí),在文本數(shù)據(jù)中使用0來替換,反之使用1來替換。
from PIL import Image '''將圖片轉(zhuǎn)換成文檔,使用0,1分別替代空白和數(shù)字''' pic = Image.open('/Users/wangxingfan/Desktop/1.png') path = open('/Users/wangxingfan/Desktop/1.txt','a') width = pic.size[0] height = pic.size[1] for i in range(0,width): for j in range(0,height): c_RGB = pic.getpixel((i,j))#獲取該像素所對(duì)應(yīng)的RGB值 if c_RGB[0]+c_RGB[1]+c_RGB[2]>0:#白色 path.write('0') elif c_RGB[0]+c_RGB[1]+c_RGB[2]==0:#黑色 path.write('1') else: pass path.write('\n') path.close()
(2)訓(xùn)練集的構(gòu)建。首先想到的是將(1)中圖片處理后的文本數(shù)據(jù)構(gòu)建成list形式,所以訓(xùn)練集將是二維數(shù)組,形如
[[1,0,1,1,0,,,,,0,1],[0,1,1,1,10,,,,],[0,0,1,0,,,],,,,,]
所以我們構(gòu)建函數(shù)處理訓(xùn)練集數(shù)據(jù)。
2。代碼
簡單的總結(jié)這個(gè)算法,就是將測試數(shù)據(jù)向量化,逐個(gè)和同樣向量化的訓(xùn)練數(shù)據(jù)進(jìn)行kNN運(yùn)算,求的最短距離出現(xiàn)最多的分類就是我們要的分類。建立訓(xùn)練集的過程就是將文件數(shù)據(jù)向量化的過程。
#!/user/bin/env python #-*- coding:utf-8 -*- from os import listdir#獲取文件目錄下所有文件 ''' from PIL import Image #將圖片轉(zhuǎn)換成文檔,使用0,1分別替代空白和數(shù)字 pic = Image.open('/Users/wangxingfan/Desktop/1.png') path = open('/Users/wangxingfan/Desktop/1.txt','a') width = pic.size[0] height = pic.size[1] for i in range(0,width): for j in range(0,height): c_RGB = pic.getpixel((i,j))#獲取該像素所對(duì)應(yīng)的RGB值 if c_RGB[0]+c_RGB[1]+c_RGB[2]>0:#白色 path.write('0') elif c_RGB[0]+c_RGB[1]+c_RGB[2]==0:#黑色 path.write('1') else: pass path.write('\n') path.close() ''' import numpy as np import operator as opt def kNN(dataSet, labels, testData, k): '''首先明確列表不能想加減,dataSet是數(shù)組形式,而對(duì)于下面的test函數(shù),testData只是一列,相當(dāng)于列表,所以在進(jìn)行加減時(shí),需要將其轉(zhuǎn)換為數(shù)組,我們使用np下的tile函數(shù)來實(shí)現(xiàn)''' testDatasize = dataSet.shape[0]#獲取dataSet的總行數(shù) dataSet = dataSet.astype('float64')#不進(jìn)行轉(zhuǎn)換則報(bào)錯(cuò) testData1 = np.tile(testData,(testDatasize,1))#使用tile函數(shù)返回多個(gè)重復(fù)構(gòu)成的數(shù)組 testData1 = testData1.astype('float64') distSquareMat = (dataSet - testData1) ** 2 # 計(jì)算差值的平方 distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和,axis=0則按列計(jì)算 distances = distSquareSums ** 0.5 # 開根號(hào),得出每個(gè)樣本到測試點(diǎn)的距離 sortedIndices = distances.argsort() # 排序,得到排序后的下標(biāo) indices = sortedIndices[:k] # 取最小的k個(gè) labelCount = {} # 存儲(chǔ)每個(gè)label的出現(xiàn)次數(shù),出現(xiàn)次數(shù)最多的就是我們要選擇的類別 for i in indices: label = labels[i] labelCount[label] = labelCount.get(label, 0) + 1 # 次數(shù)加一,使用字典的get方法,第一次出現(xiàn)時(shí)默認(rèn)值是0 sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) # 對(duì)label出現(xiàn)的次數(shù)從大到小進(jìn)行排序 return sortedCount[0][0] # 返回出現(xiàn)次數(shù)最大的label #定義函數(shù)讀取某個(gè)文件,返回該文件組成的數(shù)組 def file_data(fname): arr = [] path = open(fname) for i in range(0,32): line = path.readline() for j in range(0,32): arr.append(line[j]) return arr #建立訓(xùn)練數(shù)據(jù)集 def train_data(): lables = [] file_list = listdir('/學(xué)習(xí)/視頻課程/源碼/第7周/testandtraindata/traindata/') trainarr = np.zeros((len(file_list),1024)) for i in range(0,len(file_list)): file = '/學(xué)習(xí)/視頻課程/源碼/第7周/testandtraindata/traindata/'+file_list[i] lables.append(file_list[i].split('_')[0])#獲取對(duì)應(yīng)的文件類別 trainarr[i,:] = file_data(file)#取所有列的第一個(gè)數(shù)據(jù) return trainarr,lables #測試函數(shù) def test(): j = 0 k = 0 trainarr,lables = train_data() testdata_list = listdir('/學(xué)習(xí)/視頻課程/源碼/第7周/testandtraindata/testdata/') for i in range(0,len(testdata_list)):#逐個(gè)去測試 testfile = '/學(xué)習(xí)/視頻課程/源碼/第7周/testandtraindata/testdata/'+testdata_list[i] testdata1 = file_data(testfile) result = kNN(trainarr,lables,testdata1,k=3) print(result+',real_number:'+testdata_list[i].split('_')[0]) if result == testdata_list[i].split('_')[0]: j +=1 else: k +=1 print('辨識(shí)成功率:'+j/(k+j)) test()
輸出結(jié)果為:
3。幾個(gè)知識(shí)點(diǎn)代碼說明
(1)
numpy.tile
p = np.array([0,0,0]) np.tile(p,(3,1))#表示columns方向重復(fù)三次,index方向不變 Out[12]: array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) np.tile(p,(1,3))#表示index方向重復(fù)三次,行還是一行 Out[13]: array([[0, 0, 0, 0, 0, 0, 0, 0, 0]])
(2)
array[1,:]
表示取所有列的第【索引1】個(gè)數(shù)據(jù)(也就是第二行數(shù)據(jù))
a = np.array([[1,1,1],[2,2,2],[3,3,3],[4,4,4]]) a[1,:] Out[21]: array([2, 2, 2]) a[:,1]#所有行的第二列數(shù)據(jù) Out[22]: array([1, 2, 3, 4])
(3)list并不能進(jìn)行加減計(jì)算,需要使用numpy將數(shù)據(jù)轉(zhuǎn)換為數(shù)組形式,且在使用例如:arr1+arr2時(shí),需要兩個(gè)數(shù)組的維度相同,在某個(gè)緯度上的數(shù)據(jù)長度也相同。
(4)使用os模塊下的listdir,可以顯示所有該文件夾下的文件,以列表的形式返回。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
