当前位置:   article > 正文

k-近邻算法_k近邻选择法

k近邻选择法

1. 算法概述:是一种基本分类和回归的算法。k近邻法的输入为实例的特征向量,对应于特征空间的点;输出为实例的类别,可以取多类。k近邻法假设给定一个训练数据集,其中的实例类别已定。分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过多数表决等方式进行预测。因此,k近邻不具有显示的学习过程。k近邻实际上是利用训练数据集对特征向量空间进行划分,并作为其分类的“模型”。k值的选择、距离度量及分类决策规则是k近邻法的三个基本要素。k-近邻法于1968年由Cover和Hart提出。(简单的说就是:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,在这k个实例的多数都属于某个类,就把这个新的输入实例分为这个类。)

k近邻算法

输入:训练数据集

                                      T=\left\{(x_1,y_1),(x_2,y_2),...(x_N,y_N) \right \}

其中,x_i\in X\subseteq R^{n}为实例的特征向量,y_{i}\in Y=\left \{ c_1,c_2,..., c_K\right \}为实例的类别,i=1,2,...,N;实例特征向量x

输出:实例x所属的类y。

(1)根据给定的距离度量,在训练数据集T中找到与x最近邻的k个点,涵盖这k个点的x的邻域记作N_k(x)

(2)在N_k(x)中根据分类决策规则(如多数表决)决定x的类别y:

                                     y=arg \max_{c_{j}} \sum_{x_{i}\in N_k(x)}I(y_{i}=c_{j}),\quad i=1,2,...,K (1.1)

式(1.1)中,I 为指示函数,即当y_i=c_j时 I为1,否则I为0。

k近邻法的情况是k=1的情况,称为最近邻算法。对于输入的实例点(特征向量)x,最近邻法将训练数据集中与x最近邻点的类作为x的类。

\Rightarrowk近邻没有显示学习的过程

 

2 k近邻模型

k近邻模型对应于对特征空间的划分。模型由三个基本要素组成:距离度量、k值选择和分类决策规则

2.1 模型

k近邻算法中,当训练集、距离度量(如欧式距离)、k值及分类决策规则(如多数表决)确定后,对于任何一个新的输入实例,它所属的类唯一地确定。这相当于根据上述要素将特征空间划分为一些子空间,确定子空间里的每个点所属的类。

特征空间中,对每个训练实例点x_{i},距离该点比其他点更近的所有点组成一个区域,叫做单元。每个训练实例点都拥有一个单元,所有训练实例点的单元构成对特征空间的一个划分。最近邻法将实例x_{i}的类y_{i}作为其单元中所有点的类标记。这样,每个单元的实例点的类别是确实的。

2.2 距离度量

特征空间中两个实例点的距离是两个实例点相似程度的反映。k近邻模型的特征一般是n维实数向量空间R^{n}。使用的距离是欧式距离,但也可以是其他距离,如更一般的L_{p}距离或Minkowski距离。

设特征空间X是n维实例向量空间R^{n}x_{i},x_{j}\in X,x_{i}=(x_{i}^{(1)},x_{i}^{(2)},...,x_{i}^{(n)})^{T},x_{j}=(x_{j}^{(1)},x_{j}^{(2)},...,x_{j}^{(n)})^{T}x_{i},x_{j}L_{p}距离定义为 

                                                           L_{p}(x_{i},x_{j})=\left (\sum_{l=1}^{n}\left | x_{i}^{(l)}-x_{j}^{(l)} \right |^{p} \right )^{\frac{1}{p}} \quad \quad (2.1)

这里p\geq 1,当p=2时,称为欧式距离,即

                                                          L_{2}(x_{i},x_{j})=\left (\sum_{l=1}^{n}\left | x_{i}^{(l)}-x_{j}^{(l)} \right |^{2} \right )^{\frac{1}{2}} \quad \quad (2.2)

p=1时,称为曼哈顿距离,即

                                                         L_{1}(x_{i},x_{j})=\sum_{l=1}^{n}\left | x_{i}^{(l)}-x_{j}^{(l)} \right | \quad \quad (2.3)

p=\infty时,它是各个坐标距离的最大值,即

                                                        L_{\infty}(x_{i},x_{j})=\max_{l}\left | x_{i}^{(l)}-x_{j}^{(l)} \right | \quad \quad (2.4)

如图所示,给出了二维空间中p取不同值时,与原点的L_{p}距离为1   (L_{p}=1)  的点图形。

例1:已知二维空间的3个点x_1=(1,1)^{T},x_2=(5,1)^{T},...,x_3=(4,4)^{T},试求在p 取不同值时,L_{p}距离下的x_{1}的最近邻点。

解答过程如下:

2.3 k值的选择

k值的选择会对k近邻法的结果产生重大影响

如果选择较小的k值,就相当于用较小的领域的训练实例进行选择,“学习”的近似误差会减小,只有与输入实例较近的(相似的)训练实例才会对预测结果起作用。但缺点是“学习”的估计误差会增大,预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,k值的减小就意味着整体模型变得复杂,容易发生过拟合。

如果选择较大的K值,就相当于用较大领域中的训练实例进行预测。其优点是可以减少学习的估计误差,但缺点是近似误差会增大。这时与输入实例较远的训练实例也会对预测作用,使预测发生错误。k值的增大意味着整体模型变得简单。

在应用中,k值一般取一个比较小的数值,通常采用交叉验证法来选取最优的k值。

2.4 分类决策规则

k近邻法中的分类决策规则往往是多数表决,即由输入实例的k个邻近的训练实例中的多数类决定输入实例的类。

多数表决规则有如下解释:如果分类的损失函数为0-1损失函数,分类函数为

                                                      f:R^{n}\rightarrow \left \{ c_1,c_2,...c_k \right \}

那么误分类的概率是:

                                                     p(Y\neq f(x))=1-p(Y=f(x))

对给定的实例x\in X,其最近邻的k个训练实例点构成集合N_k(x)。如果涵盖N_k(x)的区域的类别是c_{j},那么误分类率是

                                                     \frac{1}{k}\sum _{x_{i}\in N_{k}(x)}I(y_{i}\neq c_{j})=1-\frac{1}{k}\sum _{x_{i}\in N_{k}(x)}I(y_{i}= c_{j})

要使误分类率最小即经验风险最小,就要使\sum_{x_{i}\in N_{k}(x)}I(y_{i}=c_{j}) 最大,所以采取多数表决规则等价于经验风险最小化。

 

3. k近邻的实现:kd树

实现k近邻法时,主要考虑的是如何对训练数据进行快速k-近邻搜索。k近邻算法最简单的实现方法是线性扫描。这时要计算输入实例与每个训练实例的距离。当训练集很大时,计算非常耗时,这种方法是不可行的。

为了提高k近邻搜索的效率,可以考虑使用特殊的结构存储训练数据,以减少计算距离的次数。

3.1构造kd树

kd树是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是二叉树,表示对k维空间的一个划分。构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一系列的k维超矩形区域。kd树的每个结点对应一个k维超平面区域。

构造kd树的方法如下:构造根结点,使得根结点对应于k维空间中包含所有实例点的超矩形曲区域;通过下面的递归方法,不断地对k维空间进行切分,生成子结点。在超矩形区域(结点)上选择一个坐标轴和在此坐标上的一个切分点,确定一个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点);这时,实例被分为两个子区域。这个过程直到子区域内没有实例时终止。在此过程中,将实例保存在相应的结点上。

通常,依次选择坐标轴对空间切分,选择训练实例点在选定坐标轴上的中位数为切分点,这样得到的kd树是平衡的。注意,平衡的kd树搜索时的效率未必是最优的。

构建kd树的算法:

输入:k维空间数据集T=\left \{ x_1,x_2,...,x_N \right \},

其中x_i=(x_i^{(1)},x_i^{(2)},...,x_i^{(k)})^{T},i=1,2,...N;

输出:kd树

(1)开始:构造根结点,根结点对应于包含于T的k维空间的超矩形区域。

选择x^{(1)}为坐标轴,以T中所有实例的x^{(1)}坐标的中位数为切分点,将根结点对应的超矩形区域切分为两个子区域,切分由通过切分点并与坐标轴x^{(1)}垂直的超平面实现。由根结点的生成深度为1的左、右子结点,左子结点对应坐标x^{(1)}小于切分点的子区域,右子结点对应于坐标x^{(1)}大于切分点的子区域。

将落在切分超平面上的实例点保存在跟结点。

(2)重复:对深度为j的结点,选择x^{(l)}为切分的坐标轴,l=j(mod \quad k)+1,以该结点的区域中所有实例的x^{(l)}坐标的中位数为切分点,将该结点对应的超平面矩形区域切分为两个子区域,切分由通过切分点并与坐标轴x^{(l)}垂直的超平面实现。

由该结点生成深度为j+1的左、右子结点:左子结点对应坐标x^{(l)}小于切分点的子区域,右子结点对应坐标x^{(l)}大于切分点的子区域。

将落在切分超平面上的实例点保存在该结点。

(3)直到两个子区域没有实例存在时停止,从而形成kd树的区域划分。

例2. 给定一个二维空间的数据集:

                      T=\left \{ (2,3)^{T},(5,4)^{T},(9,6) ^{T},(4,7)^{T},(8,1)^{T},(7,2)^{T}\right \}

构造一个平衡kd树。

  

3.2 搜索kd树

可以看到,利用kd可以省去对大部分数据点的搜索,从而减少搜索的计算量,这里以最近邻为例加以叙述。同样的方法可以应用到k近邻中。

给定一个目标点,搜索其最近邻。首先找到包含目标点的叶结点;然后从该叶结点出发,依次回退到父结点;不断查找与目标点最邻近的结点,当确定不可能存在更接近的结点时停止。这样搜索就限制在空间的局部区域上,效率大大提高。

包含目标点的叶结点对应包含目标点的最小超矩形区域。以此叶结点的实例点作为当前的最近点。目标点的最近邻一定在以目标点为中点并通过当前最近点的超球体的内部。然后返回当前结点的父结点,如果父结点的另一子结点的超矩形区域与超球体相交,那么在相交的区域内寻找与目标点更近的实例点。如果存在这样的点,将此点作为新的当前最近点。算法转到更上一级的父结点,继续上述过程。如果父结点的另一子结点的超矩形区域与超球体不相交,或不存在比当前最近点更近的点,则停止搜索。

最近邻搜索算法

输入:已构造的kd树;目标点x

输出:x 的最近邻。

(1)在kd树中找到包含目标点的x的叶结点:从根结点出发,递归地向下访问kd树。若目标点 x 当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止。

(2)以此叶结点为“当前最近点”;

(3)递归地向上回退,在每个结点进行以下操作:

(a)如果该结点保存的实例点比当前最近点距离目标点更近,则以该实例点为“当前最近点”;

(b)当前最近点一定存在于该结点一个子结点对应的区域。检查该子结点的父结点的另一个子结点对应的区域是否有更近的点。具体地,检查另一个子结点对应的区域是否与以目标点为球心、以目标点与“当前最近点”间的距离为半径的超球体相交。

如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点。接着,递归地进行最近邻搜索;

如果不相交,向上回退。

(4)当回退到根结点时,搜索结束,最后的“当前最近点”即为x的最近邻点。

注:如果实例点的随机分布的,kd树搜索的平均计算复杂度是O(logN),这里N是训练实例数。kd数更适用于训练实例数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时,它的效率会迅速下降,几乎接近线性扫描。

例3 给定一个如图所示的kd树,根结点为A,其子结点为B,C等。树上共存储7个实例点;另有一个输入目标实例点S,求S的最近邻。

解:

①在kd树中找到包含点S的叶结点D,以D作为暂时的近似最近邻,真正最近邻一定要在以点S为中心通过D的圆内部。

②然后返回D的父结点B,在点B的另一子结点F的区域内搜索最近邻。结点F的区域与圆不相交,故而不可能有最近邻点。

③继续返回上一级父结点A,在结点A的另一个子结点C区域内搜索最近邻。结点C区域与圆相交;该区域在圆内有实例点E,且点E离S的距离比点D更近,成为新的最近邻近似;

④最后得到点E是点S的最近邻点。

 

 

4. 特点介绍

优点:精度高、对异常值不敏感、无数据输入假定;

缺点:计算复杂度高、空间复杂度高;

适用数据范围:数值型和标称型。

(1)数值型:数值型目标变量可以从无限的数值集合中取,比如2,4,10,20,40……,主要用在回归分析中;

(2)标称型:标称型目标变量的结果只从有限数值集合中获取,比如0,1,主要用在分类中。

5. 算法的一般流程:

(1)收集数据:可以使用任何方法;

(2)准备数据:距离计算所需要的数值,最好是结构化的数据格式;

(3)分析数据:可以使用任何方法;

(4)训练算法:此步骤不适用于K-近邻算法;

(5)测试算法:计算错误率;

(6)使用算法:首先需要输入样本数据和结构化的输入结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

案例一:约会网站分类系统

第一步:实践KNN分类算法代码如下

  1. def classify0(intX,dataSet,labels,k):
  2. dataSetSize=dataSet.shape[0] #表示数据集的大小
  3. '''距离计算'''
  4. diffMat=tile(intX,(dataSetSize,1))-dataSet #当前点和训练集中的对应元素相减
  5. sqDiffMat=diffMat**2 #当前点和训练集中的对应元素相减的值上面添加平方
  6. sqDistance=sqDiffMat.sum(axis=1) #将相减的值的平方累加
  7. distances=sqDistance**0.5 #求出当前点与数据集中每个点的距离
  8. sortedDistIndices=distances.argsort() #将distances的值从小到大排列,提取其对应的索引
  9. classCount={}
  10. for i in range(k):
  11. voteIlabel=labels[sortedDistIndices[i]] #确定前k个距离最小的元素所在的类别
  12. classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #通过字典的形式,统计前k个距离最小的元素所在的类别出现的频率
  13. '''classCount.items()将字典classCount分解为元组列表
  14. operator.itemgetter(1)按照第二个元素的次序对元组进行排序
  15. reverse=True表示降序,即从大到小排列'''
  16. sortedclasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
  17. return sortedclasscount[0][0]

第二步:从文本文件中解析数据

  1. def file2matrix(filename):
  2. fr=open(filename)
  3. #readlines()用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由Python 的 for... in ... 结构进行处理
  4. arrayOLines=fr.readlines()
  5. numberOfLines=len(arrayOLines) #文件行数
  6. returnMat=zeros((numberOfLines,3)) #创建返回的numpy矩阵
  7. classLabel=[]
  8. index=0
  9. for line in arrayOLines:
  10. line=line.strip() #清楚所有的回车字符
  11. listFromLine=line.split('\t') #使用'\t'将每行分割成元素列表
  12. returnMat[index,:]=listFromLine[0:3] #选取前三个文件存储到特征矩阵中
  13. classLabel.append(int(listFromLine[-1])) #将标签存储到列表classLabel
  14. index+=1
  15. return returnMat,classLabel

第三步:使用matlotlib创建散点图

import matplotlib.pyplot as plt

  1. print(array(datingDataLabels))
  2. plt.style.use('ggplot')
  3. fig=plt.figure()
  4. ax=fig.add_subplot(111)
  5. #ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingDataLabels),15.0*array(datingDataLabels))
  6. ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingDataLabels),0.2*array(datingDataLabels))
  7. #plt.xlabel('玩视频游戏所耗时间百分比')
  8. #plt.ylabel('每周所消费的冰淇淋公升数')
  9. plt.xlabel('每年获取的飞行常客里程数')
  10. plt.ylabel('玩视频游戏所耗时间百分比')
  11. plt.legend(loc='best')
  12. plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
  13. plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
  14. plt.show()

第四步,对数据进行归一化

  1. '''考虑到每年获取的飞行常客里程数远大于其他特征数,在这里使用数值归一化进行处理'''
  2. def autoNorm(dataSet):
  3. minvalue=dataSet.min(0) #获取列中的最小值
  4. maxvalue=dataSet.max(0) #获取列中的最大值
  5. ranges=maxvalue-minvalue #最大值与最小值的差
  6. m=dataSet.shape[0] #表示行数
  7. HandleDataSet=dataSet-tile(minvalue,(m,1)) #表示归一化的分母
  8. normDataSet=HandleDataSet/tile(ranges,(m,1)) #归一化的结果
  9. return normDataSet,ranges,minvalue

第五步:分类器针对约会网站进行测试

  1. def datingClassTest():
  2. hoRatio=0.10
  3. datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
  4. normMat,ranges,minvalues=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) #classify0()中的第一个元素表示测试数据,第二个元素表示分类器的训练数据
  10. print('the classifier came back with:{0}, the real answer is:{1}'.format(classifierResult,datingLabels[i]))
  11. if (classifierResult!=datingLabels[i]):
  12. errorCount+=1.0
  13. print('the total error rate is:{0}'.format(errorCount/float(numTestVecs)))

第六步:对人进行分类

  1. def classifyperson():
  2. result_list=['not at all','in small doses','in large doses']
  3. percentTats=float(input("percentage of time spent playing video games?"))
  4. ffMiles=float(input("frequent flier miles earned per year?"))
  5. iceCream=float(input("liters of ice cream consumed per year?"))
  6. datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
  7. normMat,ranges,minvalues=autoNorm(datingDataMat)
  8. inArr=array([ffMiles,percentTats,iceCream])
  9. classifierResult=classify0((inArr-minvalues)/ranges,normMat,datingLabels,3)
  10. print("You will probably like this personL: {}".format(result_list[classifierResult-1]))

构建完整的可用系统:

  1. #!/usr/bin/env python3
  2. #coding=utf-8
  3. import pandas as pd
  4. from numpy import *
  5. import operator
  6. import matplotlib.pyplot as plt
  7. import os
  8. '''(1)计算已知类别数据集中的点与当前点之间的距离
  9. (2)按照距离递增次序排列
  10. (3)选取与当前点距离最小的K个点
  11. (4)确定前K个点所在类别的出现频率
  12. (5)返回前K个点出现频率最高的类别作为当前点的预测分类'''
  13. #使用k-近邻构建分类器
  14. def classify0(intX,dataSet,labels,k):
  15. dataSetSize=dataSet.shape[0] #表示数据集的大小
  16. '''距离计算'''
  17. diffMat=tile(intX,(dataSetSize,1))-dataSet #当前点和训练集中的对应元素相减
  18. sqDiffMat=diffMat**2 #当前点和训练集中的对应元素相减的值上面添加平方
  19. sqDistance=sqDiffMat.sum(axis=1) #将相减的值的平方累加
  20. distances=sqDistance**0.5 #求出当前点与数据集中每个点的距离
  21. sortedDistIndices=distances.argsort() #将distances的值从小到大排列,提取其对应的索引
  22. classCount={}
  23. for i in range(k):
  24. voteIlabel=labels[sortedDistIndices[i]] #确定前k个距离最小的元素所在的类别
  25. classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #通过字典的形式,统计前k个距离最小的元素所在的类别出现的频率
  26. '''classCount.items()将字典classCount分解为元组列表
  27. operator.itemgetter(1)按照第二个元素的次序对元组进行排序
  28. reverse=True表示降序,即从大到小排列'''
  29. sortedclasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
  30. return sortedclasscount[0][0]
  31. '''将文本记录转换为Numpy的解析程序'''
  32. def file2matrix(filename):
  33. fr=open(filename)
  34. #readlines()用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由Python 的 for... in ... 结构进行处理
  35. arrayOLines=fr.readlines()
  36. numberOfLines=len(arrayOLines) #文件行数
  37. returnMat=zeros((numberOfLines,3)) #创建返回的numpy矩阵
  38. classLabel=[]
  39. index=0
  40. for line in arrayOLines:
  41. line=line.strip() #清楚所有的回车字符
  42. listFromLine=line.split('\t') #使用'\t'将每行分割成元素列表
  43. returnMat[index,:]=listFromLine[0:3] #选取前三个文件存储到特征矩阵中
  44. classLabel.append(int(listFromLine[-1])) #将标签存储到列表classLabel
  45. index+=1
  46. return returnMat,classLabel
  47. #datingDataMat,datingDataLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
  48. """
  49. print(array(datingDataLabels))
  50. plt.style.use('ggplot')
  51. fig=plt.figure()
  52. ax=fig.add_subplot(111)
  53. #ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingDataLabels),15.0*array(datingDataLabels))
  54. ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingDataLabels),0.2*array(datingDataLabels))
  55. #plt.xlabel('玩视频游戏所耗时间百分比')
  56. #plt.ylabel('每周所消费的冰淇淋公升数')
  57. plt.xlabel('每年获取的飞行常客里程数')
  58. plt.ylabel('玩视频游戏所耗时间百分比')
  59. plt.legend(loc='best')
  60. plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
  61. plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
  62. plt.show()
  63. """
  64. '''考虑到每年获取的飞行常客里程数远大于其他特征数,在这里使用数值归一化进行处理'''
  65. def autoNorm(dataSet):
  66. minvalue=dataSet.min(0) #获取列中的最小值
  67. maxvalue=dataSet.max(0) #获取列中的最大值
  68. ranges=maxvalue-minvalue #最大值与最小值的差
  69. m=dataSet.shape[0] #表示行数
  70. HandleDataSet=dataSet-tile(minvalue,(m,1)) #表示归一化的分母
  71. normDataSet=HandleDataSet/tile(ranges,(m,1)) #归一化的结果
  72. return normDataSet,ranges,minvalue
  73. '''用分类器针对约会网站进行测试'''
  74. def datingClassTest():
  75. hoRatio=0.10
  76. datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
  77. normMat,ranges,minvalues=autoNorm(datingDataMat)
  78. m=normMat.shape[0]
  79. numTestVecs=int(m*hoRatio)
  80. errorCount=0.0
  81. for i in range(numTestVecs):
  82. classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) #classify0()中的第一个元素表示测试数据,第二个元素表示分类器的训练数据
  83. print('the classifier came back with:{0}, the real answer is:{1}'.format(classifierResult,datingLabels[i]))
  84. if (classifierResult!=datingLabels[i]):
  85. errorCount+=1.0
  86. print('the total error rate is:{0}'.format(errorCount/float(numTestVecs)))
  87. '''对人进行分类'''
  88. def classifyperson():
  89. result_list=['not at all','in small doses','in large doses']
  90. percentTats=float(input("percentage of time spent playing video games?"))
  91. ffMiles=float(input("frequent flier miles earned per year?"))
  92. iceCream=float(input("liters of ice cream consumed per year?"))
  93. datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
  94. normMat,ranges,minvalues=autoNorm(datingDataMat)
  95. inArr=array([ffMiles,percentTats,iceCream])
  96. classifierResult=classify0((inArr-minvalues)/ranges,normMat,datingLabels,3)
  97. print("You will probably like this personL: {}".format(result_list[classifierResult-1]))

案例二:手写识别系统

第一步:将图像转化成测试向量

  1. def img2vetor(filename):
  2. returnVect=zeros((1,1024))
  3. fr=open(filename)
  4. for i in range(32):
  5. lineStr=fr.readline() #每次读取文件的一行
  6. for j in range(32):
  7. returnVect[0,32*i+j]=int(lineStr[j])
  8. return returnVect

第二步:使用K-近邻算法识别手写数字

  1. def handwritingClassTest():
  2. hwLabels=[]
  3. trainingFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\trainingDigits') #返回指定的文件夹包含的文件或文件夹的名字的列表
  4. m=len(trainingFileList)
  5. trainingMat=zeros((m,1024))
  6. for i in range(m):
  7. fileNameStr1=trainingFileList[i]
  8. fileStr1=fileNameStr1.split('.')[0]
  9. classNumStr1=int(fileStr1.split('_')[0])
  10. hwLabels.append(classNumStr1)
  11. trainingMat[i,:]=img2vetor(r'F:\python\machinelearninginaction\Ch02\trainingDigits\%s'%fileNameStr1)
  12. testFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\testDigits')
  13. errorCount=0.0
  14. mtest=len(testFileList)
  15. for i in range(mtest):
  16. fileNameStr2=testFileList[i]
  17. fileStr2=fileNameStr2.split('.')[0]
  18. classNumStr2=int(fileStr2.split('_')[0])
  19. vectorUnderTest=img2vetor(r'F:\python\machinelearninginaction\Ch02\testDigits\%s'%fileNameStr2)
  20. classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)
  21. print("the classifierResult came back with: {0}, the real answer is: {1}".format(classifierResult,classNumStr2))
  22. if (classifierResult!=classNumStr2):
  23. errorCount+=1.0
  24. print("\nthe total number of errors is:{}".format(int(errorCount)))
  25. print("\nthe total rate is:{}".format(errorCount/float(mtest)))

完整代码:

  1. #!/usr/bin/env python3
  2. #coding=utf-8
  3. import pandas as pd
  4. from numpy import *
  5. import operator
  6. import matplotlib.pyplot as plt
  7. import os
  8. '''(1)计算已知类别数据集中的点与当前点之间的距离
  9.    (2)按照距离递增次序排列
  10.    (3)选取与当前点距离最小的K个点
  11.    (4)确定前K个点所在类别的出现频率
  12.    (5)返回前K个点出现频率最高的类别作为当前点的预测分类'''
  13. #使用k-近邻构建分类器
  14. def classify0(intX,dataSet,labels,k):
  15.     dataSetSize=dataSet.shape[0] #表示数据集的大小
  16.     '''距离计算'''
  17.     diffMat=tile(intX,(dataSetSize,1))-dataSet #当前点和训练集中的对应元素相减
  18.     sqDiffMat=diffMat**2 #当前点和训练集中的对应元素相减的值上面添加平方
  19.     sqDistance=sqDiffMat.sum(axis=1) #将相减的值的平方累加
  20.     distances=sqDistance**0.5 #求出当前点与数据集中每个点的距离
  21.     sortedDistIndices=distances.argsort() #将distances的值从小到大排列,提取其对应的索引
  22.     classCount={}
  23.     for i in range(k):
  24.         voteIlabel=labels[sortedDistIndices[i]] #确定前k个距离最小的元素所在的类别
  25.         classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #通过字典的形式,统计前k个距离最小的元素所在的类别出现的频率
  26.     '''classCount.items()将字典classCount分解为元组列表
  27.        operator.itemgetter(1)按照第二个元素的次序对元组进行排序
  28.        reverse=True表示降序,即从大到小排列'''
  29.     sortedclasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
  30.     return sortedclasscount[0][0]
  31. '''将图像转换为测试向量'''
  32. def img2vetor(filename):
  33.     returnVect=zeros((1,1024))
  34.     fr=open(filename)
  35.     for i in range(32):
  36.         lineStr=fr.readline()  #每次读取文件的一行
  37.         for j in range(32):
  38.             returnVect[0,32*i+j]=int(lineStr[j])
  39.     return returnVect
  40. def handwritingClassTest():
  41.     hwLabels=[]
  42.     trainingFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\trainingDigits') #返回指定的文件夹包含的文件或文件夹的名字的列表
  43.     m=len(trainingFileList)
  44.     trainingMat=zeros((m,1024))
  45.     for i in range(m):
  46.         fileNameStr1=trainingFileList[i]
  47.         fileStr1=fileNameStr1.split('.')[0]
  48.         classNumStr1=int(fileStr1.split('_')[0])
  49.         hwLabels.append(classNumStr1)
  50.         trainingMat[i,:]=img2vetor(r'F:\python\machinelearninginaction\Ch02\trainingDigits\%s'%fileNameStr1)
  51.     testFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\testDigits')
  52.     errorCount=0.0
  53.     mtest=len(testFileList)
  54.     for i in range(mtest):
  55.         fileNameStr2=testFileList[i]
  56.         fileStr2=fileNameStr2.split('.')[0]
  57.         classNumStr2=int(fileStr2.split('_')[0])
  58.         vectorUnderTest=img2vetor(r'F:\python\machinelearninginaction\Ch02\testDigits\%s'%fileNameStr2)
  59.         classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)
  60.         print("the classifierResult came back with: {0}, the real answer is: {1}".format(classifierResult,classNumStr2))
  61.         if (classifierResult!=classNumStr2):
  62.             errorCount+=1.0
  63.     print("\nthe total number of errors is:{}".format(int(errorCount)))
  64.     print("\nthe total rate is:{}".format(errorCount/float(mtest)))
  65. handwritingClassTest()
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/354669
推荐阅读
相关标签
  

闽ICP备14008679号