使用k-近邻算法完成手写识别系统

"""
(1) 收集数据:提供文本文件
(2) 准备数据:编写函数classify0,将图像格式转换为分类器使用的list格式
(3) 分析数据:在python命令提示符中检查数据,确保它符合要求
(4) 训练算法:此步骤不适合用于k-近邻算法
(5) 测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的
区别在于测试眼gv恩是已经完成分类的数据,如果预测分类与实际类别不同则标记为一个错误
(6) 使用算法:本例没有完成此步骤,若你感兴趣可以构建完整的应用程序,从图像中提取数字
完成数字识别,美国的邮件分拣系统就是一个实际运行的类似系统
"""
from numpy import *
import os
import operator


def classify0(inX, dataSet, labels, k):
    """
    共有四个输入参数:用于分类的输入向量是inX,输入的训练样本集为dataSet
    标签向量为labels, 最后的参数k表示用于选择最邻近的数目,其中标签向量的元素数目和
    矩阵dataSet的行数相同。计算的距离为欧氏距离
    :param inX:
    :param dataSet:
    :param labels:
    :param k:
    :return:
    """
    # 计算欧氏距离
    dataSetSize = dataSet.shape[0]  # dataSet.shape[0]输出的是数据集的行数,shape[1]输出的是数据集的列数
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet  # tile函数共有两个参数,tile(A, reps), A指待输入数组,reps决定A重复的次数,整个函数用于重复数组A来构建新的数组
    sqDiffMat = diffMat ** 2  # 计算欧氏距离
    sqDistances = sqDiffMat.sum(axis=1)  # 按行求和,
    distance = sqDistances ** 0.5  # 开根号,结果为该未知数据集到每一个已知数据集的欧氏距离

    # 选择距离最小的k个点
    sortedDistIndicies = distance.argsort()  # argsort()方法返回数组值从小到大的索引
    classCount = {}

    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]  # 获取所属类别
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1  # get方法返回指定键的值,如果不存在则返回默认值(0:设置默认值为0)
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)  # items()返回字典列表操作后的迭代  sorted(可迭代对象, 自定义的比较函数, 顺序默认为Fslse,正序)
    return sortedClassCount[0][0]


def img2vector(filename):
    """
    将图像格式化处理为一个向量,我们将把一个32* 32的二进制图像矩阵转换为一个1*1024的向量
    这两前两节使用的分类器就可以处理数字图像信息了
    该函数主要功能是将图像转换为向量,哈数创建一个1*1024的NumPy数组,然后打开给定的文件,循环
    读出文件的前32行,并将每行的头32个字符存储z在NumPy数组中,最后返回一个二维数组数组
    :param filename:
    :return: returnVect
    """
    returnVect = zeros((1, 1024))  # 返回一个一行1024列的全0数组
    fr = open(filename)  # 打开文件
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0, 32*i+j] = int(lineStr[j])  # 1*1024数组
    return returnVect


def handwritingClassTest():
    """
    将数据输入到分类器,检测分类器的执行效果,该函数是测试分类器的代码
    主要功能是从os模块中导入函数listdir,它可以列出给定目录的文件名
    :return:
    """
    hwLabels = []

    # 获取目录内容以及目录的长度  训练集
    trainingFileList = os.listdir("data/trainingDigits")  # 指定目录中的文件名列表
    # print(trainingFileList)
    m = len(trainingFileList)  # 返回列表的长度
    trainingMat = zeros((m, 1024))  # 创建一个m行,1024列的矩阵

    for i in range(m):
        # 从文件名解析分类数字
        fileNameStr = trainingFileList[i]  # 取出每一个文件的文件名
        fileStr = fileNameStr.split(".")[0]  # 切分文件名和后缀,去掉后缀
        classNumStr = int(fileStr.split("_")[0])  # 切分文件名前的数字
        hwLabels.append(classNumStr)  # 将数字存入列表中
        # print(hwLabels)

        trainingMat[i, :] = img2vector("data/trainingDigits/%s" % fileNameStr)  # 二维数组

    # 测试集
    testFileList = os.listdir("data/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("data/testDigits/%s" % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
        if(classifierResult != classNumStr):
            errorCount += 1.0
    print("the total number of errors is : %d" % errorCount)
    print("the total error rate is :%f" %(errorCount/float(mTest)))


if __name__ == '__main__':
    filename = "data/testDigits/0_13.txt"
    returnVect = img2vector(filename)
    handwritingClassTest()
    # print(returnVect[0, 32:1023])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值