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

代碼

import operator

import numpy as np
from os import listdir

def classify0(inX, dataSet, labels, k):
    """
    函數說明:kNN算法,分類器

    Parameters:
        inX - 用於分類的數據(測試集)(1*m向量)
        dataSet - 用於訓練的數據(訓練集)(n*m向量array)
        labels - 分類標準(n*1向量array)
        k - kNN算法參數,選擇距離最小的k個點

    Returns:
        sortedClassCount[0][0] - 分類結果

    """
    # numpy函數shape[0]獲取dataSet的行數
    dataSetSize = dataSet.shape[0]
    # 將inX重複dataSetSize次並排成一列,即將inX賦值dataSetSize行、1列
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet   # tile:複製函數
    # 矩陣數乘:矩陣對應位置元素相乘(array()函數中矩陣的乘積可以使用np.matmul或者.dot()函數。而星號乘 (*)則表示矩陣對應位置元素相乘,與numpy.multiply()函數結果相同)
    sqDiffMat = diffMat ** 2  # 每個元素 ** 2
    # sum()所有元素相加,sum(0)列相加,sum(1)行相加
    sqDistances = sqDiffMat.sum(axis=1)
    # 開方,計算出距離
    distances = sqDistances ** 0.5  # 每個元素 ** 0.5
    # argsort函數返回的是distances值從小到大排序後的索引值
    sortedDistIndicies = distances.argsort()
    # 定義一個記錄類別次數的字典
    classCount = {}
    # 選擇距離最小的k個點
    for i in range(k):
        # 取出前k個元素的類別
        voteIlabel = labels[sortedDistIndicies[i]]
        # 字典的get()方法,返回指定鍵的值,如果值不在字典中返回0
        # 計算類別次數
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    # python3中用items()替換python2中的iteritems()
    # key = operator.itemgetter(1)根據字典的值進行排序
    # key = operator.itemgetter(0)根據字典的鍵進行排序
    # reverse降序排序字典
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    # 返回次數最多的類別,即所要分類的類別
    return sortedClassCount[0][0]

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)

    # 返回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)
        # 獲得測試集的1*1024向量,用於訓練
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print("分類返回結果爲%d\t真實結果爲%d" % (classifierResult, classNumStr))
        if classifierResult != classNumStr:
            errorCount += 1.0
    print("總共錯了%d個數據\n錯誤率爲%f%%" % (errorCount, errorCount / mTest * 100))


if __name__ == '__main__':
    textVect = img2vector("testDigits/0_0.txt")
    print(textVect[0][:32])

    handwritingClassTest()

二、運行結果

在這裏插入圖片描述

在這裏插入圖片描述

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