kNN算法實例之手寫識別系統(tǒng)

1、實戰(zhàn)背景

對于需要識別的數(shù)字已經(jīng)使用圖形處理軟件,處理成具有相同的色彩和大兄焕濉:寬高是32像素x32像素。盡管采用本文格式存儲圖像不能有效地利用內(nèi)存空間舅巷,但是為了方便理解羔味,我們將圖片轉(zhuǎn)換為文本格式

與此同時,這些文本格式存儲的數(shù)字的文件命名也很有特點钠右,格式為:數(shù)字的值_該數(shù)字的樣本序號

通過手寫knn的代碼寫在下面

from numpy import *
from matplotlib.font_manager import FontProperties
import matplotlib.lines as mlines
import  matplotlib.pyplot as plt
import operator
import os
''''
函數(shù)說明:knn算法赋元,分類器,inx是輸入的向量飒房,dataset是數(shù)據(jù)集搁凸,labels是標簽
'''''
def classify0(inX, dataSet, labels, k):
    #獲取dataSet的行數(shù)    shape[0]是行數(shù) shape[1]是列數(shù)
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1))-dataSet
    #diffMat的每一個元素都平方
    sqDiffMat = diffMat**2
    #所有列加起來
    sqDistance = sqDiffMat.sum(axis=1)
    distances = sqDistance**0.5
    #升序排序
    sortedDistIndicies = distances.argsort()
    classCount={}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]
'''
函數(shù)說明:將文本中的32*32矩陣轉(zhuǎn)化為1*1024向量存儲
'''
def img2vector(filename):
    returnVect =zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        #readline是讀取某一行的數(shù)據(jù)返回一個字符串對象
        #readlines 是讀取文件的所有行,每一行作為一個元素狠毯,保存在一個list中
        lineStr = fr.readline()
        for j in range(32) :
            #把第0行第32*i+j個元素賦值
            returnVect[0,32*i+j] = lineStr[j]
    return returnVect
def handwritingClassTest(k):
    hwLabels = []
    trainingFileList = os.listdir("trainingDigits")
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        #首先把fileNameStr按照.分割坪仇,然后把列表的第一個元素賦值給fileStr
        fileStr = fileNameStr.split(".")[0]
        #首先把filestr按照——分割,然后把列表的第一個元素轉(zhuǎn)化為int類型之后賦值給classNumStr垃你,即該文件表示的數(shù)字值
        classNumStr = int(fileStr.split("_")[0])
        hwLabels.append(classNumStr)
        # trainingMat[i,:]指的是這個矩陣第i行的所有元素
        trainingMat[i,:] = img2vector("trainingDigits/%s" % fileNameStr)
    testFileList = os.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])
        vectorUnderTest = img2vector("testDigits/%s" % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, k)
        print("預(yù)測的結(jié)果是%d,正確的結(jié)果是%d" %(classifierResult, classNumStr))
        if(classifierResult != classNumStr):
            errorCount += 1.0
    print("\n錯誤率是%f" % (errorCount/float(mTest)))

上述代碼還是用到了我們自己寫的classfi0函數(shù)椅文,不過喂很,knn算法已經(jīng)實現(xiàn)好了,我們直接用就可以了皆刺,首先要導(dǎo)入sklearn庫少辣,下面是sklearn的實現(xiàn)函數(shù)的說明。

KNneighborsClassifier參數(shù)說明:

n_neighbors:默認為5羡蛾,就是k-NN的k的值漓帅,選取最近的k個點。
weights:默認是uniform痴怨,參數(shù)可以是uniform忙干、distance,也可以是用戶自己定義的函數(shù)浪藻。uniform是均等的權(quán)重捐迫,就說所有的鄰近點的權(quán)重都是相等的。distance是不均等的權(quán)重爱葵,距離近的點比距離遠的點的影響大施戴。用戶自定義的函數(shù),接收距離的數(shù)組萌丈,返回一組維數(shù)相同的權(quán)重赞哗。
algorithm:快速k近鄰搜索算法,默認參數(shù)為auto辆雾,可以理解為算法自己決定合適的搜索算法肪笋。除此之外,用戶也可以自己指定搜索算法ball_tree度迂、kd_tree藤乙、brute方法進行搜索,brute是蠻力搜索英岭,也就是線性掃描,當訓(xùn)練集很大時湿右,計算非常耗時诅妹。kd_tree,構(gòu)造kd樹存儲數(shù)據(jù)以便對其進行快速檢索的樹形數(shù)據(jù)結(jié)構(gòu)毅人,kd樹也就是數(shù)據(jù)結(jié)構(gòu)中的二叉樹吭狡。以中值切分構(gòu)造的樹,每個結(jié)點是一個超矩形丈莺,在維數(shù)小于20時效率高划煮。ball tree是為了克服kd樹高緯失效而發(fā)明的,其構(gòu)造過程是以質(zhì)心C和半徑r分割樣本空間缔俄,每個節(jié)點是一個超球體弛秋。
leaf_size:默認是30器躏,這個是構(gòu)造的kd樹和ball樹的大小。這個值的設(shè)置會影響樹構(gòu)建的速度和搜索速度蟹略,同樣也影響著存儲樹所需的內(nèi)存大小登失。需要根據(jù)問題的性質(zhì)選擇最優(yōu)的大小。
metric:用于距離度量挖炬,默認度量是minkowski揽浙,也就是p=2的歐氏距離(歐幾里德度量)。
p:距離度量公式意敛。在上小結(jié)馅巷,我們使用歐氏距離公式進行距離度量。除此之外草姻,還有其他的度量方法钓猬,例如曼哈頓距離。這個參數(shù)默認為2碴倾,也就是默認使用歐式距離公式進行距離度量逗噩。也可以設(shè)置為1,使用曼哈頓距離公式進行距離度量跌榔。
metric_params:距離公式的其他關(guān)鍵參數(shù)异雁,這個可以不管,使用默認的None即可僧须。
n_jobs:并行處理設(shè)置纲刀。默認為1,臨近點搜索并行工作數(shù)担平。如果為-1示绊,那么CPU的所有cores都用于并行工作。

代碼

from sklearn.neighbors import KNeighborsClassifier as kNN
from numpy import *
import os
def img2vector(filename):
    returnVect =zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        #readline是讀取某一行的數(shù)據(jù)返回一個字符串對象
        #readlines 是讀取文件的所有行暂论,每一行作為一個元素面褐,保存在一個list中
        lineStr = fr.readline()
        for j in range(32) :
            #把第0行第32*i+j個元素賦值
            returnVect[0,32*i+j] = lineStr[j]
    return returnVect


def handwritingClassTest():
    # 測試集的Labels
    hwLabels = []
    # 返回trainingDigits目錄下的文件名
    trainingFileList = os.listdir('trainingDigits')
    # 返回文件夾下文件的個數(shù)
    m = len(trainingFileList)
    # 初始化訓(xùn)練的Mat矩陣,測試集
    trainingMat = zeros((m, 1024))
    # 從文件名中解析出訓(xùn)練集的類別
    for i in range(m):
        # 獲得文件的名字
        fileNameStr = trainingFileList[i]
        # 獲得分類的數(shù)字
        classNumber = int(fileNameStr.split('_')[0])
        # 將獲得的類別添加到hwLabels中
        hwLabels.append(classNumber)
        # 將每一個文件的1x1024數(shù)據(jù)存儲到trainingMat矩陣中
        trainingMat[i, :] = img2vector('trainingDigits/%s' % (fileNameStr))
    # 構(gòu)建kNN分類器
    neigh = kNN(n_neighbors=3, algorithm='auto')
    # 擬合模型, trainingMat為訓(xùn)練矩陣,hwLabels為對應(yīng)的標簽
    neigh.fit(trainingMat, hwLabels)
    # 返回testDigits目錄下的文件列表
    testFileList = os.listdir('testDigits')
    # 錯誤檢測計數(shù)
    errorCount = 0.0
    # 測試數(shù)據(jù)的數(shù)量
    mTest = len(testFileList)
    # 從文件中解析出測試集的類別并進行分類測試
    for i in range(mTest):
        # 獲得文件的名字
        fileNameStr = testFileList[i]
        # 獲得分類的數(shù)字
        classNumber = int(fileNameStr.split('_')[0])
        # 獲得測試集的1x1024向量,用于訓(xùn)練
        vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))
        # 獲得預(yù)測結(jié)果
        # classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        classifierResult = neigh.predict(vectorUnderTest)
        print("分類返回結(jié)果為%d\t真實結(jié)果為%d" % (classifierResult, classNumber))
        if (classifierResult != classNumber):
            errorCount += 1.0
    print("總共錯了%d個數(shù)據(jù)\n錯誤率為%f%%" % (errorCount, errorCount / mTest * 100))
if __name__ == '__main__':
    handwritingClassTest()
結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市取胎,隨后出現(xiàn)的幾起案子展哭,更是在濱河造成了極大的恐慌,老刑警劉巖闻蛀,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匪傍,死亡現(xiàn)場離奇詭異,居然都是意外死亡觉痛,警方通過查閱死者的電腦和手機役衡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來薪棒,“玉大人手蝎,你說我怎么就攤上這事榕莺。” “怎么了柑船?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵帽撑,是天一觀的道長。 經(jīng)常有香客問我鞍时,道長亏拉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任逆巍,我火速辦了婚禮及塘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锐极。我一直安慰自己笙僚,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布灵再。 她就那樣靜靜地躺著肋层,像睡著了一般。 火紅的嫁衣襯著肌膚如雪翎迁。 梳的紋絲不亂的頭發(fā)上栋猖,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音汪榔,去河邊找鬼蒲拉。 笑死,一個胖子當著我的面吹牛痴腌,可吹牛的內(nèi)容都是我干的雌团。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼士聪,長吁一口氣:“原來是場噩夢啊……” “哼锦援!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起剥悟,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤灵寺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后懦胞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體替久,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡凉泄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年躏尉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片后众。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡胀糜,死狀恐怖颅拦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情教藻,我是刑警寧澤距帅,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站括堤,受9級特大地震影響碌秸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悄窃,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一讥电、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧轧抗,春花似錦恩敌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至灯蝴,卻和暖如春恢口,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背绽乔。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工弧蝇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人折砸。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓看疗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親睦授。 傳聞我的和親對象是個殘疾皇子两芳,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容