ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

12 机器学习 - KNN实现手写数字识别

2021-07-08 09:54:50  阅读:150  来源: 互联网

标签:KNN ... 12 ## numSamples step train test 手写


需求

利用一个手写数字“先验数据”集,使用knn算法来实现对手写数字的自动识别;
先验数据(训练数据)集:

  • 数据维度比较大,样本数比较多。
  • 数据集包括数字0-9的手写体。
  • 每个数字大约有200个样本。
  • 每个样本保持在一个txt文件中。
  • 手写体图像本身的大小是32x32的二值图,转换到txt文件保存后,内容也是32x32个数字,0或者1,如下:
    在这里插入图片描述

数据集压缩包解压后有两个目录:

  • 目录trainingDigits存放的是大约2000个训练数据
  • 目录testDigits存放大约900个测试数据。

模型分析

本案例看起来跟前一个案例几乎风马牛不相及,但是一样可以用KNN算法来实现。没错,这就是机器学习的魅力,不过,也是机器学习的难点:模型抽象能力!

思考:

1. 手写体因为每个人,甚至每次写的字都不会完全精确一致,所以,识别手写体的关键是“相似度”

2. 既然是要求样本之间的相似度,那么,首先需要将样本进行抽象,将每个样本变成一系列特征数据(即特征向量)

3. 手写体在直观上就是一个个的图片,而图片是由上述图示中的像素点来描述的,样本的相似度其实就是像素的位置和颜色之间的组合的相似度

4. 因此,将图片的像素按照固定顺序读取到一个个的向量中,即可很好地表示手写体样本

5. 抽象出了样本向量,及相似度计算模型,即可应用KNN来实现

python实现

新建一个kNN.py脚本文件,文件里面包含四个函数:

  1. 一个用来生成将每个样本的txt文件转换为对应的一个向量,
  2. 一个用来加载整个数据集,
  3. 一个实现kNN分类算法。
  4. 最后就是实现加载、测试的函数。
#########################################
# kNN: k Nearest Neighbors

# 参数:        inX: vector to compare to existing dataset (1xN)
#             dataSet: size m data set of known vectors (NxM)
#             labels: data set labels (1xM vector)
#             k: number of neighbors to use for comparison 
            
# 输出:     多数类
#########################################

from numpy import *
import operator
import os


# KNN分类核心方法
def kNNClassify(newInput, dataSet, labels, k):
	numSamples = dataSet.shape[0]  # shape[0]代表行数

	## step 1: 计算欧式距离
	# tile(A, reps): 将A重复reps次来构造一个矩阵
	# the following copy numSamples rows for dataSet
	diff = tile(newInput, (numSamples, 1)) - dataSet  # Subtract element-wise
	squaredDiff = diff ** 2 # squared for the subtract
	squaredDist = sum(squaredDiff, axis = 1)  # sum is performed by row
	distance = squaredDist ** 0.5

	## step 2: 对距离排序
	# argsort()返回排序后的索引
	sortedDistIndices = argsort(distance)

	classCount = {}  # 定义一个空的字典
	for i in xrange(k):
		## step 3: 选择k个最小距离
		voteLabel = labels[sortedDistIndices[i]]

		## step 4: 计算类别的出现次数
		# when the key voteLabel is not in dictionary classCount, get()
		# will return 0
		classCount[voteLabel] = classCount.get(voteLabel, 0) + 1

	## step 5: 返回出现次数最多的类别作为分类结果
	maxCount = 0
	for key, value in classCount.items():
		if value > maxCount:
			maxCount = value
			maxIndex = key

	return maxIndex	

# 将图片转换为向量
def  img2vector(filename):
 	rows = 32
 	cols = 32
 	imgVector = zeros((1, rows * cols)) 
 	fileIn = open(filename)
 	for row in xrange(rows):
 		lineStr = fileIn.readline()
 		for col in xrange(cols):
 			imgVector[0, row * 32 + col] = int(lineStr[col])

 	return imgVector

# 加载数据集
def loadDataSet():
	## step 1: 读取训练数据集
	print "---Getting training set..."
	dataSetDir = 'E:/Python/ml/knn/'
	trainingFileList = os.listdir(dataSetDir + 'trainingDigits')  # 加载测试数据
	numSamples = len(trainingFileList)

	train_x = zeros((numSamples, 1024))
	train_y = []
	for i in xrange(numSamples):
		filename = trainingFileList[i]

		# get train_x
		train_x[i, :] = img2vector(dataSetDir + 'trainingDigits/%s' % filename) 

		# get label from file name such as "1_18.txt"
		label = int(filename.split('_')[0]) # return 1
		train_y.append(label)

	## step 2:读取测试数据集
	print "---Getting testing set..."
	testingFileList = os.listdir(dataSetDir + 'testDigits') # load the testing set
	numSamples = len(testingFileList)
	test_x = zeros((numSamples, 1024))
	test_y = []
	for i in xrange(numSamples):
		filename = testingFileList[i]

		# get train_x
		test_x[i, :] = img2vector(dataSetDir + 'testDigits/%s' % filename) 

		# get label from file name such as "1_18.txt"
		label = int(filename.split('_')[0]) # return 1
		test_y.append(label)

	return train_x, train_y, test_x, test_y

# 手写识别主流程
def testHandWritingClass():
	## step 1: 加载数据
	print "step 1: load data..."
	train_x, train_y, test_x, test_y = loadDataSet()

	## step 2: 模型训练.
	print "step 2: training..."
	pass

	## step 3: 测试
	print "step 3: testing..."
	numTestSamples = test_x.shape[0]
	matchCount = 0
	for i in xrange(numTestSamples):
		predict = kNNClassify(test_x[i], train_x, train_y, 3)
		if predict == test_y[i]:
			matchCount += 1
	accuracy = float(matchCount) / numTestSamples

	## step 4: 输出结果
	print "step 4: show the result..."
	print 'The classify accuracy is: %.2f%%' % (accuracy * 100)

测试非常简单,只需要在命令行中输入:

import kNN
kNN.testHandWritingClass()

输出结果如下:

step 1: load data...
---Getting training set...
---Getting testing set...
step 2: training...
step 3: testing...
step 4: show the result...
The classify accuracy is: 98.84%

标签:KNN,...,12,##,numSamples,step,train,test,手写
来源: https://blog.51cto.com/u_15294985/3007714

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有