机器学习之K-近邻算法
声明:本篇博文是学习《机器学习实战》一书的方式路程,系原创,若转载请标明来源。
1. K-近邻算法的一般流程:
(1)收集数据:可以使用任何方法(如爬虫)。
(2)准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3)分析数据:可以使用任何方法。
(4)测试算法:计算误差率。
(5)使用算法:首先需要输入样本数据和结构化的输出结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
2. K-近邻算法的伪代码和Python代码
对未知类别属性的数据集中的每个点依次执行以下操作:
(1)计算已知类别数据集中的点与当前点之间的距离。
(2)按照距离递增次序排序。
(3)选取与当前点距离最小的k个点。
(4)确定前k个点所在类别的出现频率。
(5)返回前k个点出现频率最高的类别作为当前点的预测分类。
程序代码:
def classify0(inX, dataSet, labels, k): dataSetSize = dataSet.shape[0] diffMat = 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]] classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) return sortedClassCount[0][0]
代码解释:
(1)classify0()函数的四个输入参数:inX 用于分类的输入向量,dataSet是输入的训练样本集,labels是标签向量,最后k是用于选择最近邻的数目,其中标签向量的元素数目和矩阵dataSet的行数相同。
(2)代码中测量两个对象距离的方法是欧几里得公式:

(3)shape函数是numpy.core.fromnumeric中的函数,它的功能是读取矩阵的长度,比如shape[0]就是读取矩阵第一维度的长度。它的输入参数可以使一个整数表示维度,也可以是一个矩阵。
(4)tile函数是模板numpy.lib.shape_base中的函数。函数的形式是tile(A,reps)
A的类型几乎所有类型都可以:array, list, tuple, dict, matrix以及基本数据类型int, string, float以及bool类型。
reps的类型也很多,可以是tuple,list, dict, array, int,bool.但不可以是float, string, matrix类型。行列重复copy的次数。
(5)sum函数中加入参数。sum(a,axis=0)或者是.sum(axis=1) ,axis=0 就是普通的相加 ;加入axis=1以后就是将一个矩阵的每一行向量相加。
(6)argsort函数返回的是数组值从小到大的索引值。
(7) get() 函数返回字典指定键的值,如果值不在字典中返回默认值。
(8)sorted进行排序,sorted(iterable, cmp=None, key=None, reverse=False)
iterable:是可迭代类型;
cmp:用于比较的函数,比较什么由key决定;
key:用列表元素的某个属性或函数进行作为关键字,有默认值,迭代集合中的一项;
reverse:排序规则. reverse = True 降序 或者 reverse = False 升序,有默认值。
返回值:是一个经过排序的可迭代类型,与iterable一样。
3 示例-使用K-近邻算法改进约会网站的配对效果
3.1 准备数据:从文本文件中解析数据
将待处理数据的格式改变为分类器可以接收的格式。
代码实现:
1 def file2matrix(filename): 2 fr = open(filename) 3 numberOfLines = len(fr.readlines()) #get the number of lines in the file 4 returnMat = zeros((numberOfLines,3)) #prepare matrix to return 5 classLabelVector = [] #prepare labels return 6 fr = open(filename) 7 index = 0 8 for line in fr.readlines(): 9 line = line.strip() 10 listFromLine = line.split('\t') 11 returnMat[index,:] = listFromLine[0:3] 12 classLabelVector.append(int(listFromLine[-1])) 13 index += 1 14 return returnMat,classLabelVector
代码解释:
(1)file2matrix ()函数的参数,filename接收文件名。
(2)open(路径+文件名,读写模式),读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件。
(3)readlines() 自动将文件内容分析成一个行的列表,该列表可以由 Python 的 for ... in ... 结构进行处理。
(4)len()获得列表中的元素个数。
(5)zeros(shape, dtype=float, order='C'),返回来一个给定形状和类型的用0填充的数组;
参数:shape:形状
dtype:数据类型,可选参数,默认numpy.float64
dtype类型:t ,位域,如t4代表4位
b,布尔值,true or false
i,整数,如i8(64位)
u,无符号整数,u8(64位)
f,浮点数,f8(64位)
c,浮点负数,
o,对象,
s,a,字符串,s24
u,unicode,u24
order:可选参数,c代表与c语言类似,行优先;F代表列优先
(6)strip() 方法用于移除字符串头尾指定的字符,默认删除空白符(包括'\n', '\r', '\t', ' ')。
(7)split()就是将一个字符串分裂成多个字符串组成的列表。
3.2 准备数据:归一化数值
不同的属性,其数值的取值范围不同,则计算距离时属性的权重就会无法掌控。因此,通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。其通用公式:
newValue = (oldValue-min) /(max-min)
其中min和max分别是数据集中的最小特征值和最大特征值。
代码实现:
1 def autoNorm(dataSet): 2 minVals = dataSet.min(0) 3 maxVals = dataSet.max(0) 4 ranges = maxVals - minVals 5 normDataSet = zeros(shape(dataSet)) 6 m = dataSet.shape[0] 7 normDataSet = dataSet - tile(minVals, (m,1)) 8 normDataSet = normDataSet/tile(ranges, (m,1)) #element wise divide 9 return normDataSet, ranges, minVals
3.3 测试算法:作为完整程序验证分类器
通常把已有的数据90%作为训练样本分类器,其余10%数据去测试分类器,检验分类器的正确率。
代码实现:
1 def datingClassTest(): 2 hoRatio = 0.10 #hold out 10% 3 datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file 4 normMat, ranges, minVals = autoNorm(datingDataMat) 5 m = normMat.shape[0] 6 numTestVecs = int(m*hoRatio) 7 errorCount = 0.0 8 for i in range(numTestVecs): 9 classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) 10 print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]) 11 if (classifierResult != datingLabels[i]): errorCount += 1.0 12 print "the total error rate is: %f" % (errorCount/float(numTestVecs)) 13 print errorCount
测试结果:

误差在5%,基本可以实现对结果的预测。
4.使用算法:构建完整可用系统
代码实现:
1 def classifierPerson(): 2 resultList = [u'不喜欢',u'比较喜欢',u'很喜欢'] 3 percentTats = float(raw_input(u"玩视频游戏所耗时间百分百:")) 4 ffmiles = float(raw_input(u"每年获得的飞行常客里程数:")) 5 iceCream = float(raw_input(u"每周消耗的冰淇淋公升数:")) 6 datingDataMat, datingLables = kNN.file2matrix('datingTestSet2.txt') 7 normMat,ranges,minVals = kNN.autoNorm(datingDataMat ) 8 inArr = array([ffmiles ,percentTats ,iceCream ]) 9 classifierResult = kNN.classify0((inArr-minVals )/ranges,normMat ,datingLables ,3) 10 print u"你对这个人喜欢度: %s" % resultList [classifierResult -1]
运行结果:

5 附-对数据分析的数据可视化
代码实现:
1 def show_data(): 2 dataSet,lables = kNN .file2matrix('datingTestSet2.txt') 3 jieguo = kNN .classify0([2674,8.54,8.0],dataSet ,lables ,10) 4 fig= plt.figure() 5 ax = fig.add_subplot(111) 6 ax.scatter(dataSet [:, 1], dataSet [:, 2], 7 15.0*array(lables ),15.0*array(lables)) 8 fig.show() 9 raw_input()
运行结果:


浙公网安备 33010602011771号