【機器學習】【監督學習】【算法01-實例03】K近鄰(k-nearest neighbor)-手寫識別

0 數據說明

手寫識別也是一個非常經典的應用實例。在本次應用當中,數據的格式如下:

  • File name:‘_’爲劃分,前爲標籤,後爲例子數。例如‘0_0’就是0的手寫體的第一個實例。
  • 內容:文本內容爲32×32 的1-0像素存儲的點,如果使用img可視化,可以看到黑白的數字的效果。待會需要處理成1*1024矩陣的形式。

1 數據處理

這一步需要比較注意的點是:

  1. 使用readline()方法讀取的 lineStr = fr.readline(),是字符串格式的,因此在後續填充中,使用下標的形式而不是進行整體填充
  2. 時刻注意數據類型 如我們需要的是數字類型就絕不能放一個str
from numpy import  *
from KNN import  classify0
from os import  listdir #用於獲取當前目錄下的所有文件名

#讀取一個像素進制文件並將其轉化爲1*1024矩陣的函數方法
def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()  #讀取一行,讀取出來的格式是str
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j]) #填充,注意單位的轉換
    return returnVect

2 應用實例

代碼描述:

  1. 使用os庫中的lisdir讀取訓練文件夾下的所有文件名,存儲,進行加工。分離。主要是將文件名字符串根據相應的特性進行分離。
  2. 將文件中的內容放到訓練庫中
  3. 對於測試集,也執行相似的操作,並使用之前寫好的KNN.classify0分類器進行測試。返回結果和答案。

提取(下面其實有兩步筆者認爲可以合成一步,如果有興趣的話大家可以試一試)

def handwritingClassTest():
    hwLabels = [] #存儲lable用的list
    path="C:\\Users\\70956\\Desktop\\Data Science\\Algorithm"
    trainingFileList = listdir(path+'\\trainingDigits')        #獲取所有的文件的名字
    m = len(trainingFileList)                           #一共有多少個訓練實例
    trainingMat = zeros((m,1024))                       #建立訓練矩陣
    for i in range(m):                                  #填充,獲取完整的訓練數據
        fileNameStr = trainingFileList[i]               #獲取一個名字
        fileStr = fileNameStr.split('.')[0]             #去掉後綴txt 保留前方名字
        classNumStr = int(fileStr.split('_')[0])        #去掉_後綴,保留分類標籤
        hwLabels.append(classNumStr)                    #標籤入庫
        trainingMat[i,:] = img2vector(path+"\\trainingDigits\\%s" % fileNameStr)   #將一個文件內的數據轉換成矩陣

測試

    testFileList = listdir(path+'\\testDigits')        #測試數據
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector(path+'\\testDigits\\%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print ("返回的結果是: %d, 真實的類別是: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0
    print ("\n判定錯誤的總數爲: %d" % errorCount)
    print ("\n錯誤率爲: %f" % (errorCount/float(mTest)))

從這個實例中,其實我們可以看到對於線性的結構來執行KNN算法時,其實計算量是非常大的:
900個測試用例,2000個距離(訓練用例),每次計算需要1024個特徵參與。結果是18億次。筆者的筆記本大概需要35秒左右。
試想如果在具體的十萬級別的數據,或者是維度更大,計算量可能都…
90020001024=1,843,200,000900*2000*1024=1,843,200,000‬
如果讀者有接觸過數據結構,那麼可能會想到我們在學習這門課程的時候學完線性表後,也考慮過這個問題(如果你的老師有用這種引入的例子的話),因此樹結構就是非常有必要。
在KNN中,我們在理論部分也提到這個問題,在應用中我們確實也會碰到這個問題。
因此,我們在下次的章節。我們嘗試解釋KD樹(K-Dimension)結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章