手写识别系统
说明:
将数据集文件 ‘digits.zip’ 解压至当前文件夹
定义将图像转换为向量函数
# 导入程序所需要的模块
import numpy as np
import operator
from os import listdir
# 将32*32的二进制图像矩阵转换为1*1024向量
def img2vector(filename):
# 存储图片像素的向量维度是1x1024
# 创建1*1024零向量
returnVect = np.zeros((1, 1024))
# 打开文件
fr = open(filename)
# 按行读取
for i in range(32):
# .readline() 和 .readlines() 之间的差异是后者一次读取整个文件
# .readline() 每次只读取一行
lineStr = fr.readline()
#每一行的前32个元素依次添加到returnVect中
for j in range(32):
returnVect[0, 32*i+j] = int(lineStr[j])
# 返回转换后的1*1024向量
return returnVect
#测试img2vector函数,然后与文本编辑器打开的文件进行比较。
returnVect=img2vector("./digits/trainingDigits/0_0.txt")
returnVect[0,0:31]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
定义 k 近邻算法
def classify0(inX, dataSet, labels, k): # inX是测试集,dataSet是训练集,lebels是训练样本标签,k是取的最近邻个数
dataSetSize = dataSet.shape[0] # 训练样本个数
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # np.tile: 重复n次
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5 # distance是inX与dataSet的欧氏距离
sortedDistIndicies = distances.argsort() # 返回排序从小到达的索引位置
classCount = {} # 字典存储k近邻不同label出现的次数
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # 对应label加1,classCount中若无此key,则默认为0
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # operator.itemgetter 获取对象的哪个维度的数据
return sortedClassCount[0][0] # 返回k近邻中所属类别最多的哪一类
定义手写数字识别系统函数
def handwritingClassTest():
# 训练样本的类别标签
hwLabels = []
#导入训练集,函数listdir可以列出给定目录的文件名。
trainingFileList = listdir('./digits/trainingDigits')
#返回文件夹下文件的个数
m = len(trainingFileList)
#初始化训练矩阵
trainingMat = np.zeros((m, 1024))
#从文件名中解析出训练集的类别
for i in range(m):
#fileNameStr得到的是每个文件名称,例如"0_0.txt"
fileNameStr = trainingFileList[i]
#去掉“.txt”,剩下“0_0”
fileStr = fileNameStr.split('.')[0]
# 按下划线‘_' 划分“0_0”,取第一个元素为类别标签
classNumStr = int(fileStr.split('_')[0])
#将获得的类别添加到 hwLabels中
hwLabels.append(classNumStr)
#将每一个文件的1x1024数据存储到trainingMat矩阵中
trainingMat[i, :] = img2vector('./digits/trainingDigits/%s' % fileNameStr)
# 测试样本
#导入测试集,函数listdir可以列出给定目录的文件名。
testFileList = listdir('./digits/testDigits') #iterate through the test set
#错误检测计数,初始为0
errorCount = 0.0
#测试数据的数量
mTest = len(testFileList)
for i in range(mTest):
# fileNameStr 得到的是每个文件名称,例如"0_0.txt"
fileNameStr = testFileList[i]
#去掉“.txt”,剩下“0_0”
fileStr = fileNameStr.split('.')[0]
# 按下划线‘_' 划分“0_0”,取第一个元素为类别标签
classNumStr = int(fileStr.split('_')[0])
#获得测试集的1x1024向量
vectorUnderTest = img2vector('./digits/testDigits/%s' % fileNameStr)
# 调用knn函数
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 1)
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)))
handwritingClassTest()
参考文档: