机器学习实战学习笔记(二)-KNN算法(2)-使用KNN算法进行手写数字的识别
概要
目的
构造使用k-近邻分类器的手写识别系统。为了简单起见,这里构造只能识别数字0到9分类器
数据格式
文件名包含了标签
内部是图片转化成的txt格式
步骤
图像转化为测试向量
必须将图像格式化处理为一个向量。 我们将把一个32 x32的二进制图像矩阵转换为1 x 1024的向量,这样前两节使用的分类器就可以处理数字图像信息了.
# 打开文件
def imgvector(filename):
returnVect=np.zeros((1,1024))
fr=open(filename,'r',encoding='utf-8')
for i in range(32):
lineStr=fr.readline()
for j in range(32):
returnVect[0,32*i+j]=int(lineStr[j])
return returnVect
测试算法
1.获取目录的内容
2.读取目录的文件名因为它包含了分类的标签
3.读取每张图片(txt文档)的向量
4.读取测试集,进行训练,输出结果
5.统计最终结果
# 手写测试
def handwritingClassTest():
hwLabels=[]
trainingFileList=listdir('KNN/testDigits')
m=len(trainingFileList)
trainingMat=np.zeros((m,1024))
for i in range(m):
filenameStr=trainingFileList[i]
fileStr=filenameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:]=imgvector('KNN/testDigits/%s'%filenameStr)
testFileList=listdir('KNN/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=imgvector('KNN/testDigits/%s'%filenameStr)
classifierResult=knnClassify(vectorUnderTest,trainingMat,hwLabels,3)
print("分类器的返回结果是%d,真正的结果是%s"%(classifierResult,classNumStr))
if classifierResult!=classNumStr:
errorCount+=1.0
print("总预测错误的次数为: %d "%errorCount)
print("总的错误率为 %f "%(errorCount/float(mTest)))
结果
我的做法是错误的,不可以使用训练接作为测试集!!!,但是还是记录下吧!
附录代码
import numpy as np
from os import listdir
import operator as op
#K近邻算法
#inX是输入的数据
#dataSet是训练的数据
#labels是标签,类别
#k是周围邻居的数量
#返回预测的类别
def knnClassify(inX,dataSet,labels,k):
#计算欧式距离
dataSetSize=dataSet.shape[0]#shape是(4,2),要获取点的数量显然是shape[0]
diffMat=np.tile(inX,(dataSetSize,1))-dataSet
'''
np.tile(inX,(dataSetSize,1))=[[0,0],[0,0],[0,0],[0,0]]
dataSet=[[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]
np.tile-dataSet=[[-1.0,-1.1],[-1.0,-1.0],[0,0],[0,-0.1]]
即([x1-x0,y1-y0],[x2-x0,y2-x0],[x3-x0,y3-y0],[x4-x0,y4-y0])
'''
sqdiffMat=diffMat**2
#([(x1-x0)**2,(y1-y0)**2],[(x2-x0)**2,(y2-x0)**2],[(x3-x0)**2,(y3-y0)**2],[(x4-x0)**2,(y4-y0)**2])
sqDistances=sqdiffMat.sum(axis=1)
#([(x1-x0)**2+y1-y0)**2],[(x2-x0)**2+(y2-x0)**2],[(x3-x0)**2+(y3-y0)**2],[(x4-x0)**2+(y4-y0)**2])
# print(sqDistances)
distances=sqDistances**0.5
#([(x1-x0)**2+(y1-y0)**2]**(0.5),[(x2-x0)**2+(y2-x0)**2]**(0.5),[(x3-x0)**2+(y3-y0)**2]**(0.5),[(x4-x0)**2+(y4-y0)**2])**(0.5)
sortedDistIndicies=distances.argsort()#按照数值大小对下标排序,[2 3 1 0]
classCount={}
#选择距离最小的k个点
for i in range(k):
votIlabel=labels[sortedDistIndicies[i]]#获取最近的K个邻居的距离,对应的目标值
# print(votIlabel)
classCount[votIlabel]=classCount.get(votIlabel,0)+1#get(key,default)当key不存在时候默认值是default
sortedClassCount = sorted(classCount.items(), key=op.itemgetter(1), reverse=True)
# [('B', 2), ('A', 1)]
return sortedClassCount[0][0]#返回与其最近的k个邻居中,出现最多的次数
# 打开文件
def imgvector(filename):
returnVect=np.zeros((1,1024))
fr=open(filename,'r',encoding='utf-8')
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():
hwLabels=[]
trainingFileList=listdir('KNN/testDigits')
m=len(trainingFileList)
trainingMat=np.zeros((m,1024))
for i in range(m):
filenameStr=trainingFileList[i]
fileStr=filenameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:]=imgvector('KNN/testDigits/%s'%filenameStr)
testFileList=listdir('KNN/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=imgvector('KNN/testDigits/%s'%filenameStr)
classifierResult=knnClassify(vectorUnderTest,trainingMat,hwLabels,3)
print("分类器的返回结果是%d,真正的结果是%s"%(classifierResult,classNumStr))
if classifierResult!=classNumStr:
errorCount+=1.0
print("总预测错误的次数为: %d "%errorCount)
print("总的错误率为 %f "%(errorCount/float(mTest)))
if __name__ == "__main__":
handwritingClassTest()
目录结构
数据集地址
https://github.com/pbharrin/machinelearninginaction
参考书籍
<>