机器学习实战_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()

二、运行结果

在这里插入图片描述

在这里插入图片描述

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