机器学习实践:手写数字识别-2

机器学习实践:手写数字识别

1、实验描述

  • 本节实验我们将利用k近邻算法对手写数字进行识别,通过python命令行构建k近邻算法函数,输入实验提供的数据,进行数据分类,查看分类结果和错误率。通过本实验的学习,我们将掌握k近邻算法的基本原理和及其分类过程等内容

  • 实验时长:45分钟

  • 主要步骤:

    • 数据准备

    • Anaconda环境部署

    • 编写文本转换向量函数

    • 编写k近邻分类器函数

    • 编写调用测试函数

2、实验环境

  • 虚拟机数量:1

  • 系统版本:CentOS 7.5

  • Python 3.5

3、相关技能

  • Python编程
  • Anaconda使用
  • k近邻分类算法

4、相关知识点

  • 从文本文件中解析和导入数据

  • k近邻

5、实现效果

  • 打印每个数据文件的分类数据及错误率的结果,如下图

在这里插入图片描述

图 1

6、实验步骤

6.1准备工作

6.1.1准备数据集

6.1.2拷贝并解压数据

[zkpk@master ~]$ cd experiment/KNN
[zkpk@master KNN]$ unzip digit.zip

6.1.3数据介绍:解压完成后digits目录下有两个文件夹,分别是:

6.1.3.1trainingDigits:训练数据,1935个文件,每个数字大约200个文件。

6.1.3.2testDigits:测试数据,947个文件,每个数字大约100个文件。

[zkpk@master KNN]$ cd digits
[zkpk@master digits]$ ls

在这里插入图片描述

图 2

6.1.3.3每个文件中存储一个手写的数字,文件的命名类似`0_7.txt`,第一个数字`0`表示文件中的手写数字是0,后面的`7`是序号。

6.1.3.4我们使用目录trainingDigits中的数据训练分类器,使用目录testDigits中的数据测试分类器的效果。两组数据没有重叠,你可以检查一下这些文件夹的文件是否符合要求。根据这些数据我们开始实现KNN算法。

6.1.3.5该数据原本是32*32的黑白图片数据,这里为了方便理解,我们提供的是由图像转换为的文本格式数据,如下

在这里插入图片描述

图 3

6.2Anaconda环境安装部署

6.2.1Anaconda是一个用于科学计算的Python发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本python并存、切换以及各种第三方包安装问题。Anaconda利用工具/命令conda来进行package和environment的管理,并且已经包含了Python和相关的配套工具

6.2.2切换到root用户(密码为zkpk),安装Anaconda包依赖bzip2包,如果确认已安装则可跳过此步骤

[zkpk@master digits]$ cd
[zkpk@master ~]$ su
[root@master zkpk]$ yum install -y bzip2

6.2.3回到zkpk用户,从公共目录下拷贝Anaconda软件包到zkpk家目录下

[root@master zkpk]$ exit
[zkpk@master ~]$ cd /home/zkpk/tgz
[zkpk@master tgz]$ pwd
/home/zkpk/tgz
[zkpk@master tgz]$ cp Anaconda3-4.0.0-Linux-x86_64.sh  ~/
[zkpk@master tgz]$ cd

在这里插入图片描述

图 4

6.2.4使用命令安装部署

6.2.4.1使用bash安装Anaconda,看到如下提示,回车继续

[zkpk@master ~]$ bash Anaconda3-4.0.0-Linux-x86_64.sh

在这里插入图片描述

图 5

6.2.4.2出现许可证界面输入yes

在这里插入图片描述

图 6

6.2.4.3看到如下提示,继续回车确定,指定安装目录,开始安装

在这里插入图片描述

图 7

6.2.4.4安装完成会提示配置Anaconda 的环境变量,输入yes即可

在这里插入图片描述

图 8

6.2.4.5使得添加进去的环境变量生效

[zkpk@master ~]$ source ~/.bashrc

6.2.4.6验证是否安装成功
在这里插入图片描述

图 9

6.2.4.7这里需要配置相关包的下载源,我们配置国内镜像源,从而加快下载软件的速度;执行如下命令即可

[zkpk@master ~]$conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
[zkpk@master ~]$conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
[zkpk@master ~]$conda config --set show_channel_urls yes

6.2.4.8创建实验需要的虚拟环境,使用如下命令,表示创建一个名字为“zkbc”的python3.5的虚拟环境

[zkpk@master ~]$ conda create -n zkbc python=3.5

6.2.4.9终端将询问是否安装依赖,输入y开始安装
在这里插入图片描述

图 10

6.2.4.10进入虚拟环境,此时我们就进入了一个与本机环境隔离的python环境中

[zkpk@master ~]$ source activate zkbc

6.2.4.11如何退出虚拟环境

(zkbc) [zkpk@master ~]$ source deactivate

6.3开始代码编写

6.3.1进入虚拟环境中

[zkpk@master ~]$ source activate zkbc

6.3.2利用conda安装实验需要的安装包,期间输入y让安装继续,安装完成后,进入python命令行中;安装过程中,输入y让安装继续

(zkbc)[zkpk@master ~]$ conda install numpy
(zkbc)[zkpk@master ~]$ python

6.3.3导入实验需要用到的相关包

>>>from os import listdir
>>>import operator
>>>import numpy as np

6.3.4我们自定义一个将数据处理成一个向量的函数tovector,该函数首先创建了一个1*1024的Numpy数组returnVect,然后打开指定的文件路径下的数据文件,循环读取文件的前32行,并将每行的前32列的值存储在数组returnVect中,这里其实就是将每一个数据文件转换成一个向量。(方法编写完成后需要回车两次,才能退出该方法编写,继续编写下面的代码)

>>>def tovector(filename):
...    # 创建向量
...    returnVect = np.zeros((1,1024))
...    # 打开数据文件,读取每行内容
...    fr = open(filename)
...    for i in range(32):	# 因为文件共32行
...        # 读取每一行
...        lineStr = fr.readline()
...        # 将每行前 32 字符转成 int 存入向量
...        for j in range(32):	# 因为文件每行,共32个字符
...            returnVect[0,32*i+j] = int(lineStr[j])
...    return returnVect

在这里插入图片描述

图 11

6.3.5KNN算法的核心是:计算“距离”,这里我们定义KNN算法实现函数KNNAlg,函数的参数包括:

6.3.5.1inputvector:用于分类的输入向量

6.3.5.2trainDataSet:输入的训练样本集

6.3.5.3labels:样本数据的类标签向量

6.3.5.4k:用于选择最近邻居的数目

6.3.6算法实现过程为:

6.3.6.1计算已知类别数据集中的点与当前点之间的距离;

6.3.6.2按照距离递增次序排序;

6.3.6.3选取与当前点距离最小的k个点;

6.3.6.4确定前k个点所在类别的出现频率;

6.3.6.5返回前k个点出现频率最高的类别作为当前点的预测分类

>>>def KnnAlg(inputvector, trainDataSet, labels, k):
...    # 获取样本数据数量
...    trainDataSize = trainDataSet.shape[0]
...    # 矩阵运算,计算测试数据与每个样本数据对应数据项的差值
...    diffMat = np.tile(inputvector, (trainDataSize,1)) - trainDataSet
...    # sqDistances 上一步骤结果平方和
...    sqDiffMat = diffMat**2
...    sqDistances = sqDiffMat.sum(axis=1)
...    # 取平方根,得到距离向量
...    distances = sqDistances**0.5
...    # 按照距离从低到高排序,返回对应元素的索引
...    sortedDistIndicies = distances.argsort()     
...    classCount={}          
...    # 依次取出最近的样本数据
...    for i in range(k):
...        # 记录该样本数据所属的类别
...        voteIlabel = labels[sortedDistIndicies[i]]
...        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
...    # 对类别出现的频次进行排序,从高到低
...    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
...    # 返回出现频次最高的类别
...    return sortedClassCount[0][0]

在这里插入图片描述

图 12

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

6.3.8我们已经定义好了能够将数据处理成分类器识别的函数,接下来我们定义测试函数handwritingClassTest读取数据文件并将数据输入处理函数,再输入到分类器函数中,检测分类器的执行效果

6.3.9测试函数的步骤:

6.3.9.1读取训练数据(手写图片数据)到向量,从数据文件名中提取类别标签列表(每个向量对应的真实的数字)

6.3.9.2读取测试数据到向量,并从数据文件名中提取类别标签

6.3.9.3执行KNN算法对测试数据进行测试,得到分类结果

6.3.9.4与实际的类别标签进行对比,记录分类错误率

6.3.9.5打印每个数据文件的分类数据及错误率作为最终的结果

>>>def handwritingClassTest():
...    # 定义样本数据的类标签列表
...    hwLabels = []
...    # 读取训练数据文件列表
...    trainingFileList = listdir('/home/zkpk/experiment/KNN/digits/trainingDigits')
...    m = len(trainingFileList)
...    # 初始化训练数据矩阵(M*1024)
...    trainingMat = np.zeros((m,1024))
...    # 依次读取所有训练数据到数据矩阵
...    for i in range(m):
...        # 提取文件名中的数字
...        fileNameStr = trainingFileList[i]
...        fileStr = fileNameStr.split('.')[0]
...        classNumStr = int(fileStr.split('_')[0])
...        hwLabels.append(classNumStr)
...        # 将训练数据存入矩阵
...        trainingMat[i,:] = tovector('/home/zkpk/experiment/KNN/digits/trainingDigits/%s' % fileNameStr)
...    # 读取测试数据列表
...    testFileList = listdir('/home/zkpk/experiment/KNN/digits/testDigits')
...    # 初始化错误率
...    errorCount = 0.0
...    mTest = len(testFileList)
...    # 循环测试每个测试数据文件
...    for i in range(mTest):
...        # 提取文件名中的数字标识
...        fileNameStr = testFileList[i]
...        fileStr = fileNameStr.split('.')[0]
...        classNumStr = int(fileStr.split('_')[0])
...        # 调用tovector函数提取数据向量
...        vectorUnderTest = tovector('/home/zkpk/experiment/KNN/digits/testDigits/%s' % fileNameStr)
...        # 调用KnnAlg分类器函数对测试数据文件进行分类
...        classifierResult = KnnAlg(vectorUnderTest, trainingMat, hwLabels, 3)
...        # 打印KNN算法分类结果和真实的分类
...        print ("the classifier came back with: %d, the real answer is: %d" %(classifierResult, classNumStr))
...        # 判断KNN算法结果是否准确
...        if (classifierResult != classNumStr): errorCount += 1.0
...    # 打印错误率
...    print("\nthe total number of errors is: %d" % errorCount)
...    print("\nthe total error rate is: %f" % (errorCount/float(mTest)))

在这里插入图片描述

图 13

6.3.10至此我们需要定义的函数已经定义完成,共包括文本转换向量函数tovector、KNN分类器算法KnnAlg、测试算法handwritingClassTest

6.3.11最后我们调用测试函数handwritingClassTest,查看终端返回的分类结果

>>>handwritingClassTest()

在这里插入图片描述

图 14

6.3.12可以看到分类错误的有11个,错误比率约为1.16%,这个错误率已经比较低了,而在k近邻算法中改变变量k的值、修改函数handwritingClassTest随机选取训练样本、改变训练样本的数目,都会对k近邻算法的错误率产生影响,感兴趣的话可以改变这些变量值,观察错误率的变化

7、参考答案

在这里插入图片描述

图 15

8、总结

本实验使用k近邻算法,对手写数字图片转换成的文本数据进行分类预测。通过本节实验我们应当掌握了k近邻算法的基本原理及其分类过程,我们可以看到k近邻算法的核心是“距离”计算,而另一个影响分类准确的关键因素就是k值的选择,大家也可以尝试改变本实验中给定的k值,对比不同k值下的分类准确度。
分类错误的有11个,错误比率约为1.16%,这个错误率已经比较低了,而在k近邻算法中改变变量k的值、修改函数handwritingClassTest随机选取训练样本、改变训练样本的数目,都会对k近邻算法的错误率产生影响,感兴趣的话可以改变这些变量值,观察错误率的变化

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JTZ001

你的鼓励是我创作的最大动力?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值