接着上一篇(这里),把这一章学习完。
kNN算法其实并没有其他机器学习算法的“训练算法”的过程,他的执行过程更像是一种统计的过程。他是一种基于实例的学习算法,需要存储所需要的数据集。如果数据集很大将会需要很大的存储空间,时间开销也肯呢个会非常大。
这一张的第二个例子是识别手写数字。书已经给出了trainingDigits和testDigits两个文件夹,里面是0~9每个数字的二进制”图像”的txt,实际情况下通过处理图片可以比较容易得到这些数据。
如下:
我们首先我们需要提取txt文件中的数据,将这些数据存储到一个测试集中便于直接使用之前编写的分类函数。
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
接下来需要读取文件夹中所有txt文件中的数据进行分类和运算,并且使用之前编写的classify0函数进行分类。
(ps:python换行可以在语句后打 \ ,另起一行接着编写)
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits')
m = len(trainingFileList)
trainingMat = 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,:] = 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 "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))
最后运行结果如下:
最后附上本节完整的kNN.py代码:
#encoding:utf-8
from numpy import *
import operator
from os import listdir
#创建数据集
def createDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group, labels
#kNN实现0
def classify0(inX,dataset,labels,k):
#shape 返回行列数,shape[0]是行数,有多少元组
datasetsize = dataset.shape[0]
#tile 复制inX,使其与dataset一样大小
diffmat = tile(inX,(datasetsize,1)) - dataset
#**表示乘方
sqdiffmat = diffmat ** 2
#按行将计算结果求和
sqdistances = sqdiffmat.sum(axis=1)
distances = sqdistances ** 0.5
#使用argsort排序,返回索引值
sortedDistIndicies = distances.argsort()
#用于计数,计算结果
classcount = {}
for i in range(k) :
voteIlabel = labels[sortedDistIndicies[i]]
classcount[voteIlabel] = classcount.get(voteIlabel,0)+1
sortedClasscount = sorted(classcount.iteritems(),key=operator.itemgetter(1),reverse=True) #按照第二个元素降序排列
#返回出现次数最多的那一个label的值
return sortedClasscount[0][0]
#从txt中读入数据
def file2matrix(filename):
fr = open(filename)
#打开文件,按行读入
arrayOLines = fr.readlines()
#获得文件行数
numberOfLines = len(arrayOLines)
#创建m行n列的零矩阵
returnMat = zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
#删除行前面的空格
listFromLine = line.split('\t')
#根据分隔符划分
returnMat[index,:] = listFromLine[0:3]
#取得每一行的内容存起来
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
#归一化数据
def autoNorm(dataSet):
#找出样本集中的最小值
minVals = dataSet.min(0)
#找出样本集中的最大值
maxVals = dataSet.max(0)
#最大最小值之间的差值
ranges = maxVals - minVals
#创建与样本集一样大小的零矩阵
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
#样本集中的元素与最小值的差值
normDataSet = dataSet - tile(minVals, (m,1))
#数据相除,归一化
normDataSet = normDataSet/tile(ranges, (m,1))
return normDataSet, ranges, minVals
def datingClassTest():
hoRatio = 0.10
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
#设置测试个数
numTestVecs = int(m*hoRatio)
#记录错误数量
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])
if (classifierResult != datingLabels[i]): errorCount += 1.0
#计算错误率
print "the total error rate is: %f" % (errorCount/float(numTestVecs))
print errorCount
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
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits')
m = len(trainingFileList)
trainingMat = 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,:] = 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 "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))