您的位置:首页 > 编程语言

《机器学习实战》第二章k-近邻算法代码分析

2018-07-26 20:41 197 查看

本文对《机器学习实战》中k-近邻算法的实现代码进行分析。k-近邻算法在此不再做过多的说明,可以参考下面这篇文章https://blog.csdn.net/lzalgorithm/article/details/81081418

接下来,我们就正式开始对代码进行分析解读。

首先,导入科学计算包Numpy和运算符模块,并定义creatDataSet()函数来创建数据集和标签

[code]from numpy import *
import operator

def creatDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) #训练集数据
labels = ['A','A','B','B'] #对应的标签
return group,labels

接下来我们实现kNN算法,这里先给出kNN算法实现的伪代码,便于大家理解

(1)计算已知类别数据集中的点与当前点之间的距离;

(2)按照距离递增次序排序;

(3)选取与当前点距离最小的k个点;

(4)确定前k个点所在类别的出现频率 ;

(5)返回前k个点出现频率最高的类别作为当前点的预测分类。

[code]def classify0(inX,dataSet,labels,k): #inX是用于分类的输入向量,dataSet是输入的训练样本集,
#labels为标签,k为选择最近邻居的数目
dataSetSize = dataSet.shape[0] #获得训练样本集的行数
'''计算距离'''
diffMat = tile(inX,(dataSetSize,1))-dataSet #使用tile()函数将inX重复dataSetSize行,1列,然后再与dataSet相减
sqDiffMat = diffMat**2 #平方
sqDistances = sqDiffMat.sum(axis=1) #行相加
distances = sqDistances**0.5 #开根号
sortedDistIndicies = distances.argsort() #将元素按照由小到大的顺序返回下标
classCount = {}
'''选择距离最小的点'''
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]] #返回距离最近前k个点的标签
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1 #对这k个最近的点的类别进行统计,这里判断classCount里有没有voteIlabel,如果有则get()返回1,没有则get()返回0
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #将所统计的类别进行降序排序
return sortedClassCount[0][0] #返回发生频率最高的元组标签

接下来,使用kNN算法来改进约会网站的配对效果,在我们将所给的特征数据输入到分类器之前,必须先将数据的格式处理为分类器可以接受的格式,创建file2matrix函数来处理此问题,该函数输入为文件名字符串,输出为训练样本矩阵和类标签向量。

[code]'''将文本记录到转换Numpy的解析程序'''
def file2matrix(filename):
fr = open(filename) #打开文件
arrayOLines = fr.readlines() #读取文件每一行的内容
numberOfLines = len(arrayOLines) #得到文件的行数
returnMat = zeros((numberOfLines,3)) #创建一个行数为文件行数numberOfLines,列数为3的全零矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip() #截取掉所有回车符
listFromLine = line.split('\t') #使用tab字符\t将上一步得到的整行数据分割成一个元素列表
returnMat[index,:] = listFromLine[0:3] #将列表中前3个元素存入矩阵中
classLabelVector.append(int(listFromLine[-1])) #将列表最后一个元素,即标签存入标签向量里
index += 1
return returnMat,classLabelVector

至此,我们已经导入了数据并将数据转化为我们想要的格式。接下来我们对特征值进行归一化。

[code]def autoNorm(dataSet):
minVals = dataSet.min(0) #取最小值
maxVals = dataSet.max(0) #取最大值
ranges = maxVals-minVals #最大最小值之前的差
normDataSet = zeros(shape(dataSet)) #生成一个和dataSet形状一样的零矩阵
m = dataSet.shape[0] #获取dataSet第一维的值,因为dataSet有1000x3个值,所以为1000
normDataSet = dataSet-tile(minVals,(m,1)) #用tile()函数将minVals转化为何dataSet相同的大小的矩阵,然后相减
normDataSet = normDataSet/tile(ranges,(m,1)) #用tile()函数将ranges转化为何dataSet相同的大小的矩阵,然后用上一步得到的normDataSet除以它
return normDataSet,ranges,minVals

接下来我们对分类器的效果进行测试,创建datingClassTest()函数。

[code]def datingClassTest():
hoRatio = 0.10 #数据集中用作测试数据的比率
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #转化数据格式
normMat,ranges,minVals = autoNorm(datingDataMat) #归一化数据
m = normMat.shape[0] #得到样本的数量
numTestVecs = int(m*hoRatio) #选取10%的样本用来测试分类器
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 #如果分类与实际标签不一样,errorCount加1
print("the total error rate is: %f" % (errorCount/float(numTestVecs))) #打印总出错误率

对分类器测试完毕之后,就可以用这个分类器来对人们分类,只要输入某个人的信息,程序就会给出喜欢这个人程度的预测值。

[code]def classifyPerson():
resultList = ['not at all','in small doses','in large doses'] #结果列表
percentTats = float(input("percentage of time  spent playing video games?")) #输入玩游戏时间的比重
ffMiles = float(input("frequent flier miles earned per year?")) #输入每年飞行里程数
iceCream = float(input("liters of ice cream consumed per year?")) #输入每年所吃冰激凌的量
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #转化数据格式
normMat,ranges,minVals = autoNorm(datingDataMat) #归一化
inArr = array([percentTats,ffMiles,iceCream]) #创建一个数组用来存放之前输入的信息
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3) #用kNN算法预测
print("You will probably like this person: ",resultList[classifierResult - 1]) #打印出预测结果

再举一个kNN算法应用的例子——手写识别系统。首先我们要把图像转化为测试向量。

[code]def img2vector(filename):
returnVect = zeros((1,1024)) #创建一个1x1024的零向量
fr = open(filename) #打开文件
for i in range(32):
lineStr = fr.readline()	 #读取文件的每一行
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j]) #将每行的头32个字符存储在向量中
return returnVect

接下来,将数据输入到分类器,检测分类器的执行效果。

[code]def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits') #获取目录内容并存储在列表里
m = len(trainingFileList) #获得列表长度,即目录中有多少文件
trainingMat = zeros((m,1024)) #创建一个mx1024的矩阵
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 = testFileLis
4000
t[i] #得到文件名和扩展名
fileStr = fileNameStr.split('.')[0] #得到文件名
classNumStr = int(fileStr.split('_')[0]) #得到该文件所存储的数字
vectorUnderTest = img2vector('trainingDigits/%s' % fileNameStr) #图像转向量,创建测试集
classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3) #使用kNN算法进行分类
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult,classNumStr)) #打印出分类结果和真实结果
if (classifierResult != classNumStr): errorCount +=1.0 #如果分类结果与实际结果不一样,错误数加1
print("\nthe total number of errors is: %d" % errorCount) #打印总错误数
print("\nthe total error rate is: %f" % (errorCount/float(mTest))) #打印总错误率

本文用Python对kNN算法进行了实现,并通过两个例子来讲述如何使用kNN算法,希望能给大家带来一些帮助。

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: