1.文章说明
此文章参考机器学习实战一书,具体的理论知识可以参考该书。本文的初衷只是为了做一个复习,将学过的知识加以整理,其中不免有一定的错误。
2.K-近邻算法的原理介绍
k-近邻算法通过测量不同的特征值之间的距离进行分类。它的工作原理如下:存在一个样本的数据集合,也成为训练样本集合。并且样本集中的每个数据都存在标签,即我们知道样本集中的数据与其对应的分类的关系。输入没有标签的数据之后,将输入数据的特征值玉样本集中数据的特征值之间进行一个距离的计算,。提取样本集中特征最相似的分类标签。一般说来,我们只选择样本集中特征值最相似的前k个数据,这就是k-近邻中k值的由来。通常k是不大于20的常数。
3.K-经历算法的过程
- 计算一直类别数据集中的点与当前点的距离;
- 按照距离依次进行排序:
- 选取与当前距离最小的k个点:
- 确定前k个点所在类别的出现频率。
本文通过一个在线约会网站的实例对kNN算法进行一个简单的实现。问题的背景是海伦利用在线网站寻找合适的约会的对象,经过一段时间的她发现了三种类型的人,不喜欢的,魅力一般的,极具魅力的。其中这些约会对象的数据都放在一个.txt的文本中,通过收集一定的数据,她的样本主要包含以下三种特征:每年获得的飞行里程,每周玩游戏与看视频时间百分比,每周消费冰激凌公升数。
5.实现过程
首先需要读取放在文本中的这些约会者的信息,假设一共有n个人,那么通过读取可以得到一个nx3的矩阵,并得到训练集中相对应的约会者的标签,这是一个nx1的矩阵向量。对应的Python实现代码如下所示:
#定义读取文件的函数,将文信息解析为可用的数据
def file2matrix(filename):
fr=open(filename)
arraylines=fr.readlines() #得到文件的行数
numberOfLines=len(arraylines)
returnMat=zeros((numberOfLines,3)) #定义返回的矩阵
classLabelVector=[] #定义返回的类别向量
index=0
for line in arraylines:
line=line.strip()
listfromline=line.split('\t')
returnMat[index,:]=listfromline[0:3]
classLabelVector.append(int(listfromline[-1]))
index += 1
return returnMat,classLabelVector
因为考虑到有的特征值的值比较大,例如飞行的总里程,为了避免有的特征值对于结果的影响,需要将特征值进行一个归一化的处理,将所有的特征值都归一化到0-1之
间,将每个特征值除以最大值与最小值的差值就可以将特征值进行归一化。将上一步得到的矩阵进行归一化处理后就可以得到一个值都在0-1的矩阵,Python代码如下:
#归一化特征值,即将特征值都限定在0——1的范围内
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)) #element wise divide
return normDataSet, ranges, minVals
最后需要对训练的分类器进行一个测试,从样本集中抽取一定的样本作为测试集,通过分类处理与开始默认的分类进行一个比较,就可以得到分类的准确率。Python代码如下;
def datingClassTest():
hoRatio = 0.10 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file
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)