您当前的位置: 首页 >  机器学习

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

杨林伟 发布时间:2019-09-27 16:12:23 ,浏览量:2

需求

利用一个手写数字“先验数据”集,使用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%
关注
打赏
1688896170
查看更多评论

杨林伟

暂无认证

  • 2浏览

    0关注

    3183博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0726s