Sklearn构建k-近邻分类器用于手写数字识别

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

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

构造的系统只能识别数字0到9,目录trainingDigits中包含了大约2000个例子,每个数字大约有200个样本;目录testDigits中包含了大约900个测试数据。尽管采用文本格式存储图像不能有效地利用内存空间,但是为了方便理解,我们将图片转换为文本格式,数字的文本格式如图所示。

在这里插入图片描述
文件的名字也是有特殊含义的,格式为:数字的值_该数字的样本序号。

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

把一个32×32的二进制图像矩阵转换为1×1024的向量,这样前两节使用的分类器就可以处理数字图像信息了。

import numpy as np
import operator
from os import listdir
from sklearn.neighbors import KNeighborsClassifier as kNN

"""
Parameters:
    filename - 文件名
Returns:
    returnVect - 返回的二进制图像的1x1024向量
"""
# 函数说明:将32x32的二进制图像转换为1x1024向量。
def img2vector(filename):
    #创建1x1024零向量
    returnVect = np.zeros((1, 1024))
    #打开文件
    fr = open(filename)
    #按行读取
    for i in range(32):
        #读一行数据
        lineStr = fr.readline()
        #每一行的前32个元素依次添加到returnVect中
        for j in range(32):
            returnVect[0, 32*i+j] = int(lineStr[j])
    #返回转换后的1x1024向量
    return returnVect

# 函数说明:手写数字分类测试
def handwritingClassTest():
    #测试集的Labels
    hwLabels = []
    #返回trainingDigits目录下的文件名
    trainingFileList = listdir('trainingDigits')
    #返回文件夹下文件的个数
    m = len(trainingFileList)
    #初始化训练的Mat矩阵,测试集
    trainingMat = np.zeros((m, 1024))
    #从文件名中解析出训练集的类别
    for i in range(m):
        #获得文件的名字
        fileNameStr = trainingFileList[i]
        #获得分类的数字
        classNumber = int(fileNameStr.split('_')[0])
        #将获得的类别添加到hwLabels中
        hwLabels.append(classNumber)
        #将每一个文件的1x1024数据存储到trainingMat矩阵中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % (fileNameStr))
    #构建kNN分类器
    neigh = kNN(n_neighbors = 3, algorithm = 'auto')
    #拟合模型, trainingMat为测试矩阵,hwLabels为对应的标签
    neigh.fit(trainingMat, hwLabels)
    #返回testDigits目录下的文件列表
    testFileList = listdir('testDigits')
    #错误检测计数
    errorCount = 0.0
    #测试数据的数量
    mTest = len(testFileList)
    #从文件中解析出测试集的类别并进行分类测试
    for i in range(mTest):
        #获得文件的名字
        fileNameStr = testFileList[i]
        #获得分类的数字
        classNumber = int(fileNameStr.split('_')[0])
        #获得测试集的1x1024向量,用于训练
        vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))
        #获得预测结果
        # classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        classifierResult = neigh.predict(vectorUnderTest)
        print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))
        if(classifierResult != classNumber):
            errorCount += 1.0
    print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest * 100))


if __name__ == '__main__':
    handwritingClassTest()

>>> 
分类返回结果为9	真实结果为9
分类返回结果为9	真实结果为9
分类返回结果为9	真实结果为9
分类返回结果为9	真实结果为9
总共错了12个数据
错误率为1.268499%

上述代码使用的algorithm参数是auto,更改algorithm参数为brute,使用暴力搜索,你会发现,运行时间变长了,变为10s+。更改n_neighbors参数,你会发现,不同的值,检测精度也是不同的。可以尝试更改这些参数的设置,加深对其函数的理解。

k-近邻算法总结

k-近邻算法是分类数据最简单最有效的算法,通过两个例子(约会网站和手写数字识别)讲述了如何使用k-近邻算法构造分类器。。k-近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。k-近邻算法必须保存全部数据集,如果训练数据集的很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。

k-近邻算法的另一个缺陷是它无法给出任何数据的基础结构信息,因此也无法知晓平均实例样本和典型实例样本具有什么特征。下一章我们将使用概率测量方法处理分类问题,该算法可以解决这个问题。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
k-近邻分类器是一种简单而直观的机器学习算法,可以用于手写体数字识别。这个问题可以通过以下步骤来解决: 1. 数据集准备:首先,我们需要一个手写数字的数据集。通常,我们可以使用著名的MNIST数据集,其中包含了大量的手写数字样本。每个样本是一个28x28像素的灰度图像,标记了对应的数字标签。 2. 特征提取:对于每个样本,我们需要将其转换为特征向量。在处理图像数据时,常用的方法是将每个像素的灰度值作为特征。因此,对于MNIST数据集中的每个样本,我们可以得到一个784维的特征向量。 3. 训练阶段:在训练阶段,我们需要利用已知标签的样本来构建一个k-近邻分类器。k-近邻分类器的核心思想是,对于一个未知样本,我们将其与训练样本中的所有样本进行距离计算,并选取距离最近的k个样本。然后,通过投票的方式来确定未知样本的标签。在这个过程中,我们可以使用欧氏距离或其他相似性度量来度量样本之间的距离。 4. 测试阶段:在测试阶段,我们可以利用分类器来对未知样本进行预测。对于一个未知样本,我们可以计算其与训练样本的距离,并选择距离最近的k个训练样本。然后,通过投票来确定未知样本的标签。 5. 性能评估:为了评估分类器的性能,我们可以使用一些评估指标,如准确率、精确率、召回率等。这些指标可以帮助我们了解分类器的预测能力和对不同数字的分类准确性。 总之,通过使用k-近邻分类器,并结合适当的数据集和特征提取方法,我们可以实现手写体数字识别。这个方法简单易用,适用于初学者和小规模的手写体数字识别任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值