機器學習實戰_K近鄰算法 ——手寫數字預測(sklearn api)

一、序

機器學習實戰_K近鄰算法 ——手寫數字預測 調用的是自己編寫的分類器classify0,主要是爲了學習理論原理;在實際是項目中通常調用工具包的api接口,比如sklearn,這也體現了python的一個便利性,不用總是自己造輪子。雖然python提供了很多機器學習的工具包,但是也是在我們瞭解和熟悉算法的基本實現原理。

二、sklearn中KNeighborsClassifier的介紹

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=‘uniform’, algorithm=‘auto’, leaf_size=30, p=2, metric=‘minkowski’, metric_params=None, n_jobs=None, **kwargs)

官方api文檔:KNeighborsClassifier

1、KNeighborsClassifier的參數(官方文譯):

n_neighbors: int, 可選參數(默認爲 5)
  用於kneighbors查詢的默認鄰居的數量

weights(權重): str or callable(自定義類型), 可選參數(默認爲 ‘uniform’)
  用於預測的權重函數。可選參數如下:

  • ‘uniform’ : 統一的權重. 在每一個鄰居區域裏的點的權重都是一樣的。
  • ‘distance’ : 權重點等於他們距離的倒數。使用此函數,更近的鄰居對於所預測的點的影響更大。
  • [callable] : 一個用戶自定義的方法,此方法接收一個距離的數組,然後返回一個相同形狀並且包含權重的數組。

algorithm(算法): {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 可選參數(默認爲 ‘auto’)
  計算最近鄰居用的算法:

  • ‘ball_tree’ 使用算法BallTree
  • ‘kd_tree’ 使用算法KDTree
  • ‘brute’ 使用暴力搜索.
  • ‘auto’ 會基於傳入fit方法的內容,選擇最合適的算法。

  注意 : 如果傳入fit方法的輸入是稀疏的,將會重載參數設置,直接使用暴力搜索。

leaf_size(葉子數量): int, 可選參數(默認爲 30)
  傳入BallTree或者KDTree算法的葉子數量。此參數會影響構建、查詢BallTree或者KDTree的速度,以及存儲BallTree或者KDTree所需要的內存大小。 此可選參數根據是否是問題所需選擇性使用。

p: integer, 可選參數(默認爲 2)
  用於Minkowski metric(閔可夫斯基空間)的超參數。p = 1, 相當於使用曼哈頓距離 (l1),p = 2, 相當於使用歐幾里得距離(l2) 對於任何 p ,使用的是閔可夫斯基空間(l_p)

metric(矩陣): string or callable, 默認爲 ‘minkowski’
  用於樹的距離矩陣。默認爲閔可夫斯基空間,如果和p=2一塊使用相當於使用標準歐幾里得矩陣. 所有可用的矩陣列表請查詢 DistanceMetric 的文檔。

metric_params(矩陣參數): dict, 可選參數(默認爲 None)
  給矩陣方法使用的其他的關鍵詞參數。

n_jobs: int, 可選參數(默認爲 1)
  用於搜索鄰居的,可並行運行的任務數量。如果爲-1, 任務數量設置爲CPU核的數量。不會影響fit方法。

2、 KNeighborsClassifier的方法(官方文譯)

方法名 含義
fit(X, y) 使用X作爲訓練數據,y作爲目標值(類似於標籤)來擬合模型。
get_params([deep]) 獲取估值器的參數。
kneighbors([X, n_neighbors, return_distance]) 查找一個或幾個點的K個鄰居。
kneighbors_graph([X, n_neighbors, mode]) 計算在X數組中每個點的k鄰居的(權重)圖。
predict(X) 給提供的數據預測對應的標籤。
predict_proba(X) 返回測試數據X的概率估值。
score(X, y[, sample_weight]) 返回給定測試數據和標籤的平均準確值。
set_params(**params) 設置估值器的參數。

三、手寫數字預測(sklearn api)

1、修改內容

  • 1)、增加的代碼
    # 構造kNN分類器
    knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
    # 擬合模型,trainingMat爲測試矩陣,hwLabels爲對應標籤
    knn.fit(trainingMat, hwLabels)
  • 2)、替換的內容
       # 獲得預測結果
       classifierResult = knn.predict(vectorUnderTest)         # 替換 classifierResult = classify0(vectorUnderTest) 

2、代碼


import numpy as np
from os import listdir

from sklearn.neighbors import KNeighborsClassifier


def img2vector(filename):
    """
    函數說明:將32*32的二進制圖像轉換爲1*1024向量

    Parameters:
        filename - 文件名

    Returns:
        returnVect - 返回二進制圖像的1*1024向量

    """
    # 創建1*1024零向量
    returnVect = np.zeros((1, 1024))

    with open(filename) as fr:
        # 按行讀取
        for i in range(32):
            # 讀取一行數據
            lineStr = fr.readline()
            # 每一行的前32個數據依次存儲到returnVect中
            for j in range(32):
                returnVect[0, 32 * i + j] = int(lineStr[j])
        # 返回轉換後的1*1024向量
    return returnVect


def handwritingClassTest():
    """
    函數說明:手寫數字分類測試

    Parameters:
        None

    Returns:
        None
    """
    # 測試集的Labels
    hwLabels = []

    # 返回trainingDigits目錄下的文件名
    trainingFileList = listdir('trainingDigits')
    # 返回文件夾下文件的個數
    m = len(trainingFileList)
    # 初始化訓練的Mat矩陣(全零陣),測試集
    trainingMat = np.zeros((m, 1024))
    # 從文件名中解析出訓練集的類別
    for i in range(m):
        # 獲得文件的名字
        fileNameStr = trainingFileList[i]
        # 獲得分類的數字
        classNumStr = int(fileNameStr.split('_')[0])
        # 將獲得的類別添加到hwLabels中
        hwLabels.append(classNumStr)
        # 將每一個文件的1x1024數據存儲到trainingMat矩陣中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)

    # 構造kNN分類器
    knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
    # 擬合模型,trainingMat爲測試矩陣,hwLabels爲對應標籤
    knn.fit(trainingMat, hwLabels)

    # 返回testDigits目錄下的文件列表
    testFileList = listdir('testDigits')
    # 錯誤檢測計數
    errorCount = 0.0
    # 測試數據的數量
    mTest = len(testFileList)
    # 從文件中解析出測試集的類別並進行分類測試
    for i in range(mTest):
        # 獲得文件名字
        fileNameStr = testFileList[i]
        # 獲得分類的數字
        classNumStr = int(fileNameStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        # 獲得預測結果
        classifierResult = knn.predict(vectorUnderTest)
        print("分類返回結果爲%d\t真實結果爲%d" % (classifierResult, classNumStr))
        if classifierResult != classNumStr:
            errorCount += 1.0
    print("總共錯了%d個數據\n錯誤率爲%f%%" % (errorCount, errorCount / mTest * 100))


if __name__ == '__main__':

    handwritingClassTest()


四、運行結果

在這裏插入圖片描述

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