实验
一、示例:KNN手写识别系统
KNN手写分类器手写识别系统,这里的系统只能识别数字0-9,需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小:宽高是32像素*32像素的黑白图像。尽管采用文本格式存储图像不能有效地利用内存空间,但是为了方便理解,我们还是将图像转换为文本格式。
收集数据
trainingDigits目录中包含大约2000个例子(每个例子的内容如图),用于数据训练分类器
testDigits中包含了大约900个测试数据,用于测试分类器效果
一、实验过程
1.准备数据:将图像转换为测试向量
from numpy import *
# 将图像转换为测试向量
def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
if __name__ == '__main__':
testVector = img2vector('testDigits/0_13.txt')
print(testVector[0, 0:31])
print(testVector[0, 32:63])
结果:
2.测试算法:使用KNN算法识别手写数字
# KNN手写识别系统
import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator
from os import listdir
# 在文本文件中解析数据
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # 距离计算
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndices = distances.argsort()
classCount = {}
# 选择距离最小的K个点 把classCount分解为元组列表
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
# itemgetter为排序 为逆序,即按照最大到最小的次序
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
# 将图像转换为测试向量
def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
# 测试算法:使用KNN算法识别手写数字
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits') #获取目录内容
m = len(trainingFileList)
trainingMat = np.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)
trainingMat[i, :] = img2vector(
'trainingDigits/%s' % fileNameStr)
testFileList = listdir('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('testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("测试样本 %d, 分类器预测: %d, 真实类别: %d" %
(i+1, classifierResult, classNumStr))
if (classifierResult != classNumStr):
errorCount += 1.0
print("\n错误分类计数: %d" % errorCount)
print("\n错误分类比例: %f" % (errorCount/float(mTest)))
if __name__ == '__main__':
testVector = img2vector('testDigits/0_13.txt')
print(testVector[0, 0:31])
print(testVector[0, 32:63])
# 测试算法:使用KNN算法识别手写数字
handwritingClassTest()
结果:
总结
KNN是分类数据最简单最有效的算法,KNN是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。KNN必须保存全部数据集,如果训练数据集的很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。
KNN的缺点是它无法给出任何数据的基础结果信息,因此我们也无法知晓平均实例样本和典型实例样本具有什么特征。