使用k-近邻算法识别手写数字。

2023-05-16

在之前的文章中介绍了k-近邻算法的原理知识并且用Python实现了一个分类器,而且完成了一个简单的优化约会网站配对效果的实例。在《机器学习实战》中有关kNN的后一部分内容就是一个手写识别系统,可以识别手写的0-9的数字。下面就基于这一章的内容完成这样一个手写数字识别系统。


案例的描述以及流程介绍。

既然我们明白了kNN算法是根据计算新数据和样本数据集之间的距离,然后找到距离最小的样本的分类作为新数据的分类。所以我们也需要考虑如何计算0-9之间这十个数字的距离。首先书中已经提供了0-9数字的样本集,每个数字提供了大概200左右的样本,在trainingDigits目录下。

这里写图片描述

比如其中的0_0.txt就是数字0的第一个样本,又比如9_45.txt就是数字9的第45个实例,数字样本采用的是32*32文本存储方式:

比如:0_0.txt,从图中也能看出来像数字0。

这里写图片描述

但是提供的有些数据集并不是日常所见的数字写法,比如数字7:

这里写图片描述

由于我们后续需要计算的距离就是根据这些0和1的排列方式计算的,所以类似数字7这种写法差异的话,最后分类结果也可能有差异。如果可能的话,自己也是可以根据自己的书写习惯写样本集,然后将其转换为32*32文本存放,这样一来分类结果肯定要比这种的好一点。

至于如何将图片转换为32*32数组,可以参考之前的文章:手写数字图片二值化转换为32*32数组。

在本次案例中kNN算法的使用流程:

  1. 收集数据:提供文本文件。
  2. 准备数据:自己提供的32*32数组。
  3. 分析数据:查看数据,确保符合要求。
  4. 训练算法:此步骤不适用于k-近邻算法。
  5. 测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的区别在于测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
  6. 使用算法:将一个图片作为输入数据,然后使用分类器进行分类得到结果。

准备数据:将图像转换为测试向量。

上面已经介绍了本次的样本集是一个32*32的数组,为了使用前面的分类器,我们必须将这个32*32的数组转换为一个1*1024的向量。首先编写一个img2vector的函数,传入一个样本数据的文件名,可以将这个文件中的32*32数组转换为一个1*1024的向量。

def img2vector(filename):
    """
    将32*32的图像矩阵转化为1*1024的向量
    :param filename: 文件名
    :return:
    """
    # 制造一个空数组
    returnVect = np.zeros((1,1024))

    # 打开文件
    fr = open(filename)

    # 将矩阵转换为1*1024的
    for i in range(32):
        # 读取一行数据
        lineStr = fr.readline().strip()

        # 将每行的数字存放在数组中
        for j in range(32):
            returnVect[0, 32*i+j] = int(lineStr[j])

    return returnVect

编写一个简单的测试代码:

这里写图片描述

首先将0_13.txt作为参数传入img2vector函数中,然后使用len计算结果的长度是不是1*1024的,然后输出第一行内容,输出结果:

这里写图片描述

其中输出的testVector[0, 0:31]就是0_13.txt的第一行内容,可以打开0_13.txt查看对比一下:

这里写图片描述

能够看到结果一致,依此论推,testVector[0, 32:63]就是第二行的内容等等,所以确实是将0_13.txt的32*32数组转换为了1*1024向量数组。


测试算法:使用k-近邻算法识别手写数字。

我们在上一步中将32*32数组转化为1*1024向量数组的目的就是为了能够使用之前编写的kNN分类器。现在就可以将样本数据集输入到分类器中进行使用了。

我们先来测试一下这个算法,编写一个handwritingClassTest函数,该函数将trainingDigits目录下的所有样本进行读取,然后创建一个m*1024的训练矩阵进行存储,很显然该矩阵每一行都代表着一个图像。然后再读取testDigits目录下的测试样本集,每次读取一个文件,也就代表着一个图像,然后将其转换为1*1024数组,和原来的训练矩阵共同输入到之前的kNN分类器中进行分类。分类器会计算这个测试样本集和训练矩阵的距离,根据欧氏距离的计算方法,这个测试数据共计算m次距离,然后找到距离最近的,这个计算量还是比较巨大的。

def handwritingClassTest():
    """
    数字测试
    :return:
    """
    # 数字对应的标签,也就是数字的本身
    hwLabels = []

    # 得到目录下的所有文件名称
    trainingFileList = listdir('trainingDigits')

    # 计算共有多少个文件
    m = len(trainingFileList)

    # 构造m*1024 数组,用来存放所有的数字
    trainingMat = np.zeros((m, 1024))

    # 遍历所有的文件,将其加载到数组中
    for i in range(m):
        # 得到文件名称
        fileNameStr = trainingFileList[i]

        # 去除后面的.txt,得到有用的文件名
        fileStr = fileNameStr.split('.')[0]

        # 解析出来当前是哪个数字
        classNumStr = int(fileStr.split('_')[0])

        # 添加到标签上
        hwLabels.append(classNumStr)

        # 将文件转化为数组并存放到总的数组中
        trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)

    # 得到测试文件的目录
    testFileList = listdir('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('testDigits/%s' % fileNameStr)

        # 使用分类器得到结果
        classifierResult = kNN.classify0(vectorUnderTest, trainingMat, hwLabels, 3)

        # 打印结果
        print('使用分类器得到的结果为:%s,真实的结果为:%s' % (classifierResult, classNumStr))

        # 错误的话记录下来
        if classifierResult != classNumStr:
            errorCount += 1.0

    print('识别错误的个数为:%s' % errorCount)
    print('分类器的正确率为:%f' % (errorCount/float(mTest)))

编写一个测试代码执行这个函数:

这里写图片描述

查看一下输出结果:

这里写图片描述

可以看到错误率大概为1.2%,其实这些都是根据计算得到的结果,如果我们修改分类器k的值,或者选取不同的测试样本或者训练样本,都会影响这个错误率,不过可以看到这些训练样本集的正确率已经很高了,我们现在就可以真正的使用分类器进行识别了。


使用算法:将手写数字图片进行识别。

在测试完分类器之后,我们就可以使用了。最终我们的目的就是输入一个自己手写的数字图片,然后分类器告诉我这个数字是几。编写classifyHandwriting函数来使用完整的系统,该函数需要一个图像名称参数,然后会将这个图像转换为32*32数组,接下来转换为1*1024数组,在读取训练样本集,然后将新数据和训练样本集共同输入到分类器中得到分类结果。

def classifyHandwriting(filename):
    """
    将图片转化为01矩阵,然后使用分类器进行分类
    :return:
    """
    # 得到32*32的01数组
    imgTo01.picTo01(filename)

    # 得到对应名称的txt文件
    name01 = filename.split('.')[0]
    name01 = name01 + '.txt'

    # 将文件中的32*32 转化为1*1024的
    hwMat = img2vector(name01)

    # 数字对应的标签,也就是数字的本身
    hwLabels = []

    # 得到目录下的所有文件名称
    trainingFileList = listdir('trainingDigits')

    # 计算共有多少个文件
    m = len(trainingFileList)

    # 构造m*1024 数组,用来存放所有的数字
    trainingMat = np.zeros((m, 1024))

    # 遍历所有的文件,将其加载到数组中
    for i in range(m):
        # 得到文件名称
        fileNameStr = trainingFileList[i]

        # 去除后面的.txt,得到有用的文件名
        fileStr = fileNameStr.split('.')[0]

        # 解析出来当前是哪个数字
        classNumStr = int(fileStr.split('_')[0])

        # 添加到标签上
        hwLabels.append(classNumStr)

        # 将文件转化为数组并存放到总的数组中
        trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)

    # 进行分类
    classifierResult = kNN.classify0(hwMat, trainingMat, hwLabels, 3)

    print('使用分类器的结果为:%d' % classifierResult )

编写测试代码:

这里写图片描述

准备手写数字:

这里写图片描述

运行分类器得到结果:

这里写图片描述

能够看到识别出了数字,但是能够正确识别的关键点在于能否准确的将图片转换为32*32数组。因为使用的图片转换为32*32数组是本人简单写的一个程序,在转换过程中可能会出现问题导致分类结果不准确,如果能够用其他办法准确的将图片转换为32*32数组的话,这个分类器还是比较准确的。

全部代码及数据集地址:MachineLearningNote

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用k-近邻算法识别手写数字。 的相关文章

随机推荐

  • npm 的工作原理

    包 Package 和模块 Module 如何定义一个Package 满足如下条件都可以称为一个包 xff1a 一个文件夹包含应用程序 xff0c 使用package json来描述它 a 一个用gzip压缩的文件夹 xff0c 满足 a
  • 2023最全Postman安装使用详解

    一 Postman背景介绍 用户在开发或者调试网络程序或者是网页B S模式的程序的时候是需要一些方法来跟踪网页请求的 xff0c 用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具 今天给大家介绍的这款网页调试工具不仅可以
  • cmake 设置 debug release模式

    1 通过命令行的方式 cmake DCMAKE BUILD TYPE 61 Debug 2 set CMAKE BUILD TYPE Debug CACHE STRING 34 set build type to debug 34 或者 s
  • 华为笔试题(4)

    一 计算n x m的棋盘格子 xff08 n为横向的格子数 xff0c m为竖向的格子数 xff09 沿着各自边缘线从左上角走到右下角 xff0c 总共有多少种走法 xff0c 要求不能走回头路 xff0c 即 xff1a 只能往右和往下走
  • 安装RedisBloom插件

    前言 安装RedisBloom模块会遇到很多坑 xff0c 希望你不要和我一样踩的这么全 x1f60f 如果觉得编译麻烦 xff0c 我也上传了我编译的so文件 xff0c 可以直接加载使用 https download csdn net
  • ROS Catkin 教程之 CMakeLists.txt

    1 概览 CMakeLists txt 是用 CMake 构建系统构建 ROS 程序包的输入文件 任何兼容 CMake 的包都包含一个或多个 CMakeLists txt 文件 xff0c 用以描述怎样构建和安装代码 catkin 项目采用
  • Xsens Mti-g-710 IMU driver在Ubuntu18.04 ROS melodic中的安装使用

    Ubuntu18 04下安装的ROS melodic 如何使用Xsens Mti g 710 IMU driver xff1f 这里给出一个详细步骤说明 这里的IMU是USB接口 1安装 首先插入IMU的USB口 命令行运行 gt lsus
  • PYTHON -MYSQLDB安装遇到的问题和解决办法

    PYTHON MYSQLDB安装遇到的问题和解决办法 参考文章 xff1a xff08 1 xff09 PYTHON MYSQLDB安装遇到的问题和解决办法 xff08 2 xff09 https www cnblogs com gaosh
  • 位姿估计Robot_pose_efk的配置和使用

    Robot pose efk 用于融合里程计 xff0c 惯性测量单元和视觉里程计的传感器输出 xff0c 从而减少测量中的总体误差 了解ROS的robot pose ekf软件包中扩展卡尔曼滤波器的用法 xff1a robot pose
  • linux录屏和截图软件

    linux下的录屏和截图软件有很多 xff0c kazam集成了录屏和截图两个功能 xff0c 而且十分轻量级 xff0c 比较好用 如果是在VirtualBox虚拟机中跑linux的话 xff0c virtualbox本身就提供录屏和截图
  • APM 学习 6 --- ArduPilot 线程

    ArduPilot 学习之路 6 xff0c 线程 英文原文地址 xff1a https ardupilot org dev docs learning ardupilot threading html 理解 ArduPilot 线程 线程
  • nginx 配置多个vue,环境部署

    1 最近项目要上线 xff0c 需要通过nginx作为代理 xff0c 要发布2个VUE前端项目 xff0c 记录一下nginx conf配置文件 亲自验证 xff0c 特此记录一下 xff0c 希望能帮助向我一样 小白的人 user ro
  • freertos源码分析(1)--初始篇

    代码下载地址 xff1a https www freertos org 部分转载参考 FreeRTOS基础知识 xff1a RTOS全称为 xff1a Real Time OS xff0c 就是实时操作系统 xff0c 强调的是 xff1a
  • nginx服务占用百分之百

    一 当nginx达到100 时 xff0c 也就是服务器负载突然上升 1 利用top命令查看cpu使用率较高的php cgi进程 PID USER PR NI VIRT RES SHR S CPU MEM TIME 43 COMMAND 1
  • Gazebo教程(使用roslaunch 启动Gazebo,world以及urdf模型)

    Gazebo教程 xff08 使用roslaunch 启动Gazebo xff0c world以及urdf模型 xff09 关于如何学习ROS可以参考古月居的这篇文章 1 https www zhihu com question 35788
  • dispatch_queue_create---创建队列

    dispatch queue create span class hljs keyword const span span class hljs keyword char span label dispatch queue attr t a
  • Java多种方式解决生产者消费者问题(十分详细)

    一 问题描述 生产者消费者问题 xff08 Producer consumer problem xff09 xff0c 也称有限缓冲问题 xff08 Bounded buffer problem xff09 xff0c 是一个多线程同步问题
  • Http协议WWW-Authenticate

    HTTP协议有一个叫WWW Authenticate的头字段 xff0c 可以用于实现登录验证 它是在RFC 2617中定义的 当服务器接收到一个request xff0c 并在实现下面的代码 xff1a br http response
  • Android 运行时注解

    编译时注解点击此处 xff5e xff5e xff5e 运行时注解 以 64 BindView 为例 下面是实现步骤 新建一个 apt annotation 的 java library xff0c 然后在库中新建一个注解 xff0c 传入
  • 使用k-近邻算法识别手写数字。

    在之前的文章中介绍了k 近邻算法的原理知识并且用Python实现了一个分类器 xff0c 而且完成了一个简单的优化约会网站配对效果的实例 在 机器学习实战 中有关kNN的后一部分内容就是一个手写识别系统 xff0c 可以识别手写的0 9的数