基于k近邻(KNN)的手写数字识别

2023-05-16

作者:faaronzheng 转载请注明出处!

最近再看Machine Learning in Action. k近邻算法这一章节提供了不少例子,本着Talk is cheap的原则,我们用手写数字识别来实际测试一下。 简单的介绍一下k近邻算法(KNN):给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。如下图所示:


x为测试样本,小黑点是一类样本,小红点是另一类样本。在测试样本x的周围画一个圈,这个圈就是依据某种距离度量画出的,可以看到我们选择的是5近邻。现在我们要做出一个预测,就是这个测试样本x是属于小黑点那一类还是小红点那一类呢?很简单,我们只要看看选中的近邻中哪一类样本多就把这类样本的标签赋给测试样本就可以了。图中自然就是小黑点,所以我们预测x是小黑点。


正文:

第一步:准备实验数据。Machine Learning in Action书中的数据使用的是“手写数字数据集的光学识别”一文中的数据。具体可以参考书中的相关介绍。所有的数据是以Txt形式保存的,由32行32列的0/1元素组成。下图就是一个手写数字0的保存数据。可以看出,数字所在的位置用1表示,空白的用0表示。

除此之外,为了能识别自己手写的数字,我们在原来实验的基础上添加画板的功能,使其能采集自己手写的数字并按照相同的格式保存下来。如下图所示,当点击CustomizeTestData后会出现一个画板,当我们在画板上写上数字后,按下ESC键保存图片并退出,接下来将保存的图片处理成我们想要的格式,就可以用算法对其进行预测了。画板的实现使用了pygame。


下面是画板功能的具体实现:

import pygame
from pygame.locals import *
import math
from sys import exit
#向sys模块借一个exit函数用来退出程序
pygame.init()
#初始化pygame,为使用硬件做准备
 
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 4
  self.drawing = False
  self.last_pos = None
  self.space = 1
  # if style is True, normal solid brush
  # if style is False, png brush
  self.style = False
  # load brush style png
  self.brush = pygame.image.load("brush.png").convert_alpha()
  # set the current brush depends on size
  self.brush_now = self.brush.subsurface((0,0), (1, 1))
 
 def start_draw(self, pos):
  self.drawing = True
  self.last_pos = pos
 def end_draw(self):
  self.drawing = False
 
 def set_brush_style(self, style):
  print "* set brush style to", style
  self.style = style
 def get_brush_style(self):
  return self.style
 
 def get_current_brush(self):
  return self.brush_now
 
 def set_size(self, size):
  if size < 0.5: size = 0.5
  elif size > 32: size = 32
  print "* set brush size to", size
  self.size = size
  self.brush_now = self.brush.subsurface((0,0), (size*2, size*2))
 def get_size(self):
  return self.size
 
 def set_color(self, color):
  self.color = color
  for i in xrange(self.brush.get_width()):
   for j in xrange(self.brush.get_height()):
    self.brush.set_at((i, j),
      color + (self.brush.get_at((i, j)).a,))
 def get_color(self):
  return self.color
 
 def draw(self, pos):
  if self.drawing:
   for p in self._get_points(pos):
    # draw eveypoint between them
    if self.style == False:
     pygame.draw.circle(self.screen, self.color, p, self.size)
    else:
     self.screen.blit(self.brush_now, p)
 
   self.last_pos = pos
 
 def _get_points(self, pos):
  """ Get all points between last_point ~ now_point. """
  points = [ (self.last_pos[0], self.last_pos[1]) ]
  len_x = pos[0] - self.last_pos[0]
  len_y = pos[1] - self.last_pos[1]
  length = math.sqrt(len_x ** 2 + len_y ** 2)
  step_x = len_x / length
  step_y = len_y / length
  for i in xrange(int(length)):
   points.append(
     (points[-1][0] + step_x, points[-1][1] + step_y))
  points = map(lambda x:(int(0.5+x[0]), int(0.5+x[1])), points)
  # return light-weight, uniq integer point list
  return list(set(points))
 
class Menu():
 def __init__(self, screen):
  self.screen = screen
  self.brush = None

 def set_brush(self, brush):
  self.brush = brush

 
class Painter():
 def __init__(self):
  self.screen = pygame.display.set_mode((100, 100))
 # self.menu = pygame.display.set_mode((80, 600))
  pygame.display.set_caption("Painter")
  self.clock = pygame.time.Clock()
  self.brush = Brush(self.screen)
  self.menu = Menu(self.screen)
  self.menu.set_brush(self.brush)
 
 def run(self):
  self.screen.fill((255, 255, 255))
  while True:
   # max fps limit
   self.clock.tick(30)
   for event in pygame.event.get():
    if event.type == QUIT:
        pygame.quit()
     #   break
    elif event.type == KEYDOWN:
     # press esc to clear screen
     if event.key == K_ESCAPE:
      fname = "test.png"
      pygame.image.save(self.screen, fname)    
      pygame.quit()
      #break
    elif event.type == MOUSEBUTTONDOWN:
     # <= 74, coarse judge here can save much time
     if ((event.pos)[0] <= 74 and
       self.menu.click_button(event.pos)):
      # if not click on a functional button, do drawing
      pass
     else:
      self.brush.start_draw(event.pos)
    elif event.type == MOUSEMOTION:
     self.brush.draw(event.pos)
    elif event.type == MOUSEBUTTONUP:
     self.brush.end_draw()
    self.menu.draw()
    pygame.display.update()

KNN算法--KNN的关键在我看来是距离度量的选择。不同的距离度量会对最终的结果产生比较大的影响。首先将手写数字变化为一个一维的向量,通过计算测试样例(向量)和每个训练样本(向量)之间的距离然后进行排序。最后选最近的k个进行投票产生对测试样例的预测。


import pygame
from numpy import *
import operator
from os import listdir
from Board import *
import Tkinter
import tkFileDialog
import tkMessageBox
import Image  
from KNN import dot
pygame.init()


def classify0(inX, dataSet, labels, k):           #k控制选取最近的k个近邻然后投票
    dataSetSize = dataSet.shape[0]
    #计算欧式距离(其实比较的是两个向量之间的距离)
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    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.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]
def classify1(inX,dataSet,labels, k):
 dataSetSize = dataSet.shape[0]
 diffMat = tile(inX, (dataSetSize,1)) - dataSet
 diffMatT=(diffMat.T)
 sqDiffMat = dot(diffMat,diffMat.T)
 distances = sqrt(sqDiffMat)   
 sortedDistIndicies=distances.argsort() 
 classCount={}         
#投票
 for i in range(k):
    voteIlabel = labels[sortedDistIndicies[i]]
    classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
 return sortedClassCount[0][0]
# 将文件转化为向量
def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

def handwritingClassTest(TrainDataPath):
    hwLabels = []
    trainingFileList = listdir(TrainDataPath)           #load the training set
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector(TrainDataPath+'/%s' % fileNameStr)
    testFileList = listdir('C:/Users/HP/Desktop/MLiA_SourceCode/machinelearninginaction/Ch02/testDigits')        #iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('C:/Users/HP/Desktop/MLiA_SourceCode/machinelearninginaction/Ch02/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 "\nthe total number of errors is: %d" % errorCount
    print "\nthe total error rate is: %f" % (errorCount/float(mTest))

top = Tkinter.Tk()

def TrainDataCallBack():
    TrainDataPath=tkFileDialog.askdirectory()
    handwritingClassTest(TrainDataPath)

def CustomizeTestDataCallBack():
    board = Painter()
    board.run()
    
def TestingCustomizeTestDataCallBack():
    ResizePic()
    TransformArray()
TrainDataButton = Tkinter.Button(top, text ="TrainData", command = TrainDataCallBack)
CustomizeTestDataButton = Tkinter.Button(top, text ="CustomizeTestData", command = CustomizeTestDataCallBack)
TestingButton = Tkinter.Button(top, text ="TestingCustomizeTestData", command = TestingCustomizeTestDataCallBack)

def ResizePic():
    im = Image.open("test.png")  
    w,h = im.size  
    im_ss = im.resize((int(32), int(32)))  
    im_ss.save("test.png")  

def TransformArray():
    TestArray = zeros((1,1024))
    im = Image.open("test.png")  
    width,height = im.size  
    for h in range(0, height):  
      for w in range(0, width):  
        pixel = im.getpixel((w, h))      
        if pixel!=(255,255,255):
            TestArray[0,32*h+w]=int(1)
    handwritingTesting(TestArray)


def handwritingTesting(TestArray):
  #  TrainDataPath=tkFileDialog.askdirectory()
    TrainDataPath="C:/Users/HP/Desktop/MLiA_SourceCode/machinelearninginaction/Ch02/trainingDigits"
    hwLabels = []
    trainingFileList = listdir(TrainDataPath)           #load the training set
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector(TrainDataPath+'/%s' % fileNameStr)      
    classifierResult = classify0(TestArray, trainingMat, hwLabels, 100)
    classifierResult1 = classify1(TestArray, trainingMat, hwLabels, 100)
    print "the classifier came back with: %d"  %  classifierResult
    print "the classifier came back with: %d"  %  classifierResult1
       
TrainDataButton.pack()
CustomizeTestDataButton.pack()
TestingButton.pack()
top.mainloop()



源代码下载:faaron-KNN手写字识别



这里面我们采用了很笨的方法将测试样本与所有训练样本进行比较,更有效的方法是采用KD树。另外k的取值在这里也是固定的,更好的方法是在一个区间内网格搜索~


未完待续。。。

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

基于k近邻(KNN)的手写数字识别 的相关文章

  • 基于numpy的CNN实现,进行MNIST手写数字识别

    主要框架来自于这篇文章 xff1a https blog csdn net qq 36393962 article details 99354969 xff0c 下面会以原文来代称这篇文章 本文在原文的基础上增加了交叉熵以及mnist数据集
  • Kmeans聚类(手写数字识别)

    Kmeans算法原理 xff1a 在给定K个初始聚类中心点的情况下 xff0c xff08 1 xff09 把数据中的每个样本分到离其最近的聚类中心所代表的类中 xff08 2 xff09 分类完后计算从新每个类的中心点 xff08 取平均
  • 【TensorFlow】使用LeNet-5模型实现mnist手写数字识别

    LeNet 5 模型 LeNet 5是卷积神经网络 xff08 CNN xff09 中较简单的一个网络模型 xff0c 在学习LeNet 5之前 xff0c 最好先去了解以下卷积神经网络的基本概念与过程 LeNet 5模型总共有7层 xff
  • 机器学习(二)--- KNN(K-Nearest Neighbors)

    KNN K Nearest Neighbors 简单类比 xff08 Simple Analogy xff09 KNN xff1a 通过你周围的人来判断你是哪一类人 Tell me about your friends who your n
  • 实现基于TensorFlow的手写数字识别(1)

    一 MNIST数字识别数据集获取及处理 通过学习林大贵老师的 TensorFlow Keras深度学习人工智能实践应用 对图像处理的过程有了较浅薄的理解 在此与大家分享 同时由于上书中提供的代码下载页面失效 笔者按照书本中的内容手敲代码 如
  • 基于Hadoop的Knn算法实现

    Knn算法的核心思想是如果一个样本在特征空间中的K个最相邻的样本中的大多数属于某一个类别 则该样本也属于这个类别 并具有这个类别上样本的特性 该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别 Knn方法在类
  • K-近邻算法之鸢尾花实例 使用Spark实现KNN的Demo

    1 1 K 近邻算法 KNN 概念 K Nearest Neighbor算法又叫KNN算法 这个算法是机器学习里面一个比较经典的算法 总体来说KNN算法是相对比较容易理解的算法 定义 如果一个样本在特征空间中的k个最相似 即特征空间中最邻近
  • 机器学习(四):基于KNN算法对鸢尾花类别进行分类预测

    文章目录 专栏导读 1 KNN算法原理 2 实战案例 对鸢尾花类别分类预测 2 1确定特征和类别 2 2对特征进行处理 2 3对模型调参 选择最优参数 2 4使用分类模型进行预测 2 5评估模型 检验模型效果 3 完整代码及结果 专栏导读
  • caffe安装以及LeNet实现手写数字体识别

    0 引言 今天开始正式跳入深度学习的坑 希望自己两年半的研究生生涯中 能够在深度学习方面取得一点成绩 今天开始在服务器上弄caffe的时候遇到了很多问题 看了很多博客 最终解决了问题 现在把遇到的问题以及解决方案总结一下 本文是基于服务器已
  • KNN分类算法原理及其Matlab实现

    KNN算法原理 K近邻算法是一种简单的监督学习算法 对于给定测试样本 直接计算该样本和训练集的距离 将距离最近的k个 邻居 点的类别作为参考 作为预测结果返回 测试数据 测试数据来自林智仁的分类任务数据集 链接 https www csie
  • KNN数据分类算法的matlab仿真

    目录 1 算法概述 2 仿真效果 3 MATLAB仿真源码 1 算法概述 KNN的本质是通过距离判断待测样本和已知样本是否相似 待测样本找到与已知样本中与其距离最近的K个样本 对这k个样本 它们大多数属于哪一类别 就把待测样本归为哪一类别
  • 基于Python爬虫+KNN数字验证码识别系统——机器学习算法应用(含全部工程源码)+训练数据集

    目录 前言 总体设计 系统整体结构图 系统流程图 运行环境 Python 环境 模块实现 1 数据爬取 2 去噪与分割 3 模型训练及保存 4 准确率验证 系统测试 工程源代码下载 其它资料下载 前言 本项目利用Python爬虫技术 通过网
  • matlab中的KNN算法

    我正在研究拇指识别系统 我需要实现 KNN 算法来对我的图像进行分类 根据this 它只有 2 个测量值 通过这些测量值计算找到最近邻居的距离 但在我的例子中 我有 400 张 25 X 42 的图像 其中 200 个用于训练 200 个用
  • scikit-learn 的 KNN 如何计算概率估计?

    scikit learn中KNN算法的实现是如何计算概率估计的predict proba X method 以下示例摘自 sklearn 文档 但进行了一些修改 以便您可以理解我们在这种情况下做什么 有关更多详细信息 请参见 https s
  • 如何在 python 中使用 kNN 动态时间扭曲

    我有一个带有两个标签的时间序列数据集 0 and 1 我在用动态时间扭曲 DTW 作为使用 k 最近邻 kNN 进行分类的相似性度量 如这两篇精彩的博客文章中所述 https nbviewer jupyter org github mark
  • 朴素贝叶斯分类器 - 多重决策

    我需要知道朴素贝叶斯分类器是否 可用于生成多个决策 我不能 找到任何有证据支持的例子 多项决定 我是这个领域的新手 所以 我有点 使困惑 实际上我需要开发字符识别软件 在那里我需要确定给定的字符是什么 看来贝叶斯分类器可以用来识别 给定的字
  • 使用 TF-IDF 分数进行文本分类的 KNN

    我有一个 CSV 文件 corpus csv 其中包含语料库中以下格式的分级摘要 文本 Institute Score Abstract UoM 3 0 Hello this is abstract one UoM 3 2 Hello th
  • Sklearn KNeighborsRegressor 自定义距离度量

    我正在使用 KNeighborsRegressor 但我想将它与自定义距离函数一起使用 我的训练集是 pandas DataFrame 如下所示 week day hour minute temp humidity 0 1 9 0 1 1
  • K 最近邻算法 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 使用 KNN 算法 假设 k 5 现在我尝试通过获取 5 个最近的邻居来对未知对象进行分类 如果确定 4 个最近邻居后 接下来的 2 个
  • 属性错误:“图形”对象没有属性“节点”

    我有以下 python 代码来构建 knn 图 但出现错误 AttributeError Graph 对象没有属性 node 似乎 nx Graph 没有节点属性 但我不知道应该用它替换什么 import networkx as nx de

随机推荐