您好,欢迎访问三七文档
KNN算法实验报告一试验原理K最近邻(k-NearestNeighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成正比。该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。该方法的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。二试验步骤那么根据以上的描述,我把结合使用反余弦匹配和kNN结合的过程分成以下几个步骤:1.计算出样本数据和待分类数据的距离2.为待分类数据选择k个与其距离最小的样本3.统计出k个样本中大多数样本所属的分类4.这个分类就是待分类数据所属的分类数学表达:目标函数值可以是离散值(分类问题),也可以是连续值(回归问题).函数形势为f:n维空间R—〉一维空间R。第一步:将数据集分为训练集(DTrn)和测试集(DTES)。第二步:在测试集给定一个实例Xq;在训练集(DTrn)中找到与这个实例Xq的K-最近邻子集{X1、、、、XK},即:DKNN。第三步:计算这K-最近邻子集得目标值,经过加权平均:^f(Xq)=(f(X1)+...+f(XK))/k作为f(Xq)的近似估计。改进的地方:对kNN算法的一个明显的改进是对k个最近邻的贡献加权,将较大的权值赋给较近的近邻,相应的算法称为距离加权kNN回归算法,则公式1则修改为:^f(Xq)=(w1*f(X1)+...+wk*f(XK))/(w1+...wk)一般地距离权值wi和距离成反比关系,例如,wi近似=1/d(xq;xi).K值的选择:需要消除K值过低,预测目标容易产生变动性,同时高k值时,预测目标有过平滑现象。推定k值的有益途径是通过有效参数的数目这个概念。有效参数的数目是和k值相关的,大致等于n/k,其中,n是这个训练数据集中实例的数目。缺点:(1)在大训练集寻找最近邻的时间是难以忍受的。(2)在训练数据集中要求的观测值的数目,随着维数p的增长以指数方式增长。这是因为和最近邻的期望距离随着维数p的增多而急剧上升,除非训练数据集的大小随着p以指数方式增长。这种现象被称为“维数灾难”。解决办法有下面几个:(1)通过降维技术来减少维数,如主成分分析,因子分析,变量选择(因子选择)从而减少计算距离的时间;(2)用复杂的数据结构,如搜索树去加速最近邻的确定。这个方法经常通过公式2公式1设定“几乎是最近邻”的目标去提高搜索速度;(3)编辑训练数据去减少在训练集中的冗余和几乎是冗余的点,从而加速搜索最近邻。在个别例子中去掉在训练数据集中的一些观察点,对分类效果没有影响,原因是这些点被包围属于同类的观测点中。三注意事项KNN算法的实现要注意:1.用TreeMapString,TreeMapString,Double保存测试集和训练集。2.注意要以类目_文件名作为每个文件的key,才能避免同名不同内容的文件出现。3.注意设置JM参数,否则会出现JAVAheap溢出错误。4.本程序用向量夹角余弦计算相似度。四代码//KNN.javapackagecqu.KNN;importjava.util.ArrayList;importjava.util.Comparator;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importjava.util.PriorityQueue;//KNN算法主体类publicclassKNN{/***设置优先级队列的比较函数,距离越大,优先级越高*/privateComparatorKNNNodecomparator=newComparatorKNNNode(){publicintcompare(KNNNodeo1,KNNNodeo2){if(o1.getDistance()=o2.getDistance()){return-1;}else{return1;}}};/***获取K个不同的随机数*@paramk随机数的个数*@parammax随机数最大的范围*@return生成的随机数数组*/publicListIntegergetRandKNum(intk,intmax){ListIntegerrand=newArrayListInteger(k);for(inti=0;ik;i++){inttemp=(int)(Math.random()*max);if(!rand.contains(temp)){rand.add(temp);}else{i--;}}returnrand;}/***计算测试元组与训练元组之前的距离*@paramd1测试元组*@paramd2训练元组*@return距离值*/publicdoublecalDistance(ListDoubled1,ListDoubled2){doubledistance=0.00;for(inti=0;id1.size();i++){distance+=(d1.get(i)-d2.get(i))*(d1.get(i)-d2.get(i));}returndistance;}/***执行KNN算法,获取测试元组的类别*@paramdatas训练数据集*@paramtestData测试元组*@paramk设定的K值*@return测试元组的类别*/publicStringknn(ListListDoubledatas,ListDoubletestData,intk){PriorityQueueKNNNodepq=newPriorityQueueKNNNode(k,comparator);ListIntegerrandNum=getRandKNum(k,datas.size());for(inti=0;ik;i++){intindex=randNum.get(i);ListDoublecurrData=datas.get(index);Stringc=currData.get(currData.size()-1).toString();KNNNodenode=newKNNNode(index,calDistance(testData,currData),c);pq.add(node);}for(inti=0;idatas.size();i++){ListDoublet=datas.get(i);doubledistance=calDistance(testData,t);KNNNodetop=pq.peek();if(top.getDistance()distance){pq.remove();pq.add(newKNNNode(i,distance,t.get(t.size()-1).toString()));}}returngetMostClass(pq);}/***获取所得到的k个最近邻元组的多数类*@parampq存储k个最近近邻元组的优先级队列*@return多数类的名称*/privateStringgetMostClass(PriorityQueueKNNNodepq){MapString,IntegerclassCount=newHashMapString,Integer();intpqsize=pq.size();for(inti=0;ipqsize;i++){KNNNodenode=pq.remove();Stringc=node.getC();if(classCount.containsKey(c)){classCount.put(c,classCount.get(c)+1);}else{classCount.put(c,1);}}intmaxIndex=-1;intmaxCount=0;Object[]classes=classCount.keySet().toArray();for(inti=0;iclasses.length;i++){if(classCount.get(classes[i])maxCount){maxIndex=i;maxCount=classCount.get(classes[i]);}}returnclasses[maxIndex].toString();}}//KNNNode.javapackagecqu.KNN;publicclassKNNNode{privateintindex;//元组标号privatedoubledistance;//与测试元组的距离privateStringc;//所属类别publicKNNNode(intindex,doubledistance,Stringc){super();this.index=index;this.distance=distance;this.c=c;}publicintgetIndex(){returnindex;}publicvoidsetIndex(intindex){this.index=index;}publicdoublegetDistance(){returndistance;}publicvoidsetDistance(doubledistance){this.distance=distance;}publicStringgetC(){returnc;}publicvoidsetC(Stringc){this.c=c;}}//TestKNN.javapackagecqu.KNN;importjava.io.BufferedReader;importjava.io.File;importjava.io.FileReader;importjava.util.ArrayList;importjava.util.List;//KNN算法测试类publicclassTestKNN{/***从数据文件中读取数据*@paramdatas存储数据的集合对象*@parampath数据文件的路径*/publicvoidread(ListListDoubledatas,Stringpath){try{BufferedReaderbr=newBufferedReader(newFileReader(newFile(path)));Stringreader=br.readLine();while(reader!=null){Stringt[]=reader.split();ArrayListDoublelist
本文标题:KNN算法实验报告
链接地址:https://www.777doc.com/doc-1823940 .html