"""
(1) 收集数据:提供文本文件
(2) 准备数据:编写函数classify0,将图像格式转换为分类器使用的list格式
(3) 分析数据:在python命令提示符中检查数据,确保它符合要求
(4) 训练算法:此步骤不适合用于k-近邻算法
(5) 测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的
区别在于测试眼gv恩是已经完成分类的数据,如果预测分类与实际类别不同则标记为一个错误
(6) 使用算法:本例没有完成此步骤,若你感兴趣可以构建完整的应用程序,从图像中提取数字
完成数字识别,美国的邮件分拣系统就是一个实际运行的类似系统
"""
from numpy import *
import os
import operator
def classify0(inX, dataSet, labels, k):
"""
共有四个输入参数:用于分类的输入向量是inX,输入的训练样本集为dataSet
标签向量为labels, 最后的参数k表示用于选择最邻近的数目,其中标签向量的元素数目和
矩阵dataSet的行数相同。计算的距离为欧氏距离
:param inX:
:param dataSet:
:param labels:
:param k:
:return:
"""
# 计算欧氏距离
dataSetSize = dataSet.shape[0] # dataSet.shape[0]输出的是数据集的行数,shape[1]输出的是数据集的列数
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # tile函数共有两个参数,tile(A, reps), A指待输入数组,reps决定A重复的次数,整个函数用于重复数组A来构建新的数组
sqDiffMat = diffMat ** 2 # 计算欧氏距离
sqDistances = sqDiffMat.sum(axis=1) # 按行求和,
distance = sqDistances ** 0.5 # 开根号,结果为该未知数据集到每一个已知数据集的欧氏距离
# 选择距离最小的k个点
sortedDistIndicies = distance.argsort() # argsort()方法返回数组值从小到大的索引
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]] # 获取所属类别
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # get方法返回指定键的值,如果不存在则返回默认值(0:设置默认值为0)
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # items()返回字典列表操作后的迭代 sorted(可迭代对象, 自定义的比较函数, 顺序默认为Fslse,正序)
return sortedClassCount[0][0]
def img2vector(filename):
"""
将图像格式化处理为一个向量,我们将把一个32* 32的二进制图像矩阵转换为一个1*1024的向量
这两前两节使用的分类器就可以处理数字图像信息了
该函数主要功能是将图像转换为向量,哈数创建一个1*1024的NumPy数组,然后打开给定的文件,循环
读出文件的前32行,并将每行的头32个字符存储z在NumPy数组中,最后返回一个二维数组数组
:param filename:
:return: returnVect
"""
returnVect = zeros((1, 1024)) # 返回一个一行1024列的全0数组
fr = open(filename) # 打开文件
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0, 32*i+j] = int(lineStr[j]) # 1*1024数组
return returnVect
def handwritingClassTest():
"""
将数据输入到分类器,检测分类器的执行效果,该函数是测试分类器的代码
主要功能是从os模块中导入函数listdir,它可以列出给定目录的文件名
:return:
"""
hwLabels = []
# 获取目录内容以及目录的长度 训练集
trainingFileList = os.listdir("data/trainingDigits") # 指定目录中的文件名列表
# print(trainingFileList)
m = len(trainingFileList) # 返回列表的长度
trainingMat = zeros((m, 1024)) # 创建一个m行,1024列的矩阵
for i in range(m):
# 从文件名解析分类数字
fileNameStr = trainingFileList[i] # 取出每一个文件的文件名
fileStr = fileNameStr.split(".")[0] # 切分文件名和后缀,去掉后缀
classNumStr = int(fileStr.split("_")[0]) # 切分文件名前的数字
hwLabels.append(classNumStr) # 将数字存入列表中
# print(hwLabels)
trainingMat[i, :] = img2vector("data/trainingDigits/%s" % fileNameStr) # 二维数组
# 测试集
testFileList = os.listdir("data/testDigits")
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split(".")[0]
classNumStr = int(fileStr.split("_")[0])
vectorUnderTest = img2vector("data/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("the total number of errors is : %d" % errorCount)
print("the total error rate is :%f" %(errorCount/float(mTest)))
if __name__ == '__main__':
filename = "data/testDigits/0_13.txt"
returnVect = img2vector(filename)
handwritingClassTest()
# print(returnVect[0, 32:1023])
使用k-近邻算法完成手写识别系统
最新推荐文章于 2023-01-17 09:21:21 发布