KNN算法实验报告

时间:2024.5.2

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.用TreeMap<String,TreeMap<String,Double>>保存测试集和训练集。

2.注意要以"类目_文件名"作为每个文件的key,才能避免同名不同内容的文件出现。

3.注意设置JM参数,否则会出现JAVAheap溢出错误。

4.本程序用向量夹角余弦计算相似度。

四 代码

//KNN.java

package cqu.KNN;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.PriorityQueue;

//KNN算法主体类

public class KNN

{

/** * 设置优先级队列的比较函数,距离越大,优先级越高 */

private Comparator<KNNNode> comparator = new Comparator<KNNNode>() {

public int compare(KNNNode o1, KNNNode o2)

{

if (o1.getDistance() >= o2.getDistance())

{

return -1;

}

else

{

return 1;

}

}

};

/** * 获取K个不同的随机数 * @param k 随机数的个数 * @param max 随机数最大的范围 * @return 生成的随机数数组 */

public List<Integer> getRandKNum(int k, int max)

{

List<Integer> rand = new ArrayList<Integer>(k);

for (int i = 0; i < k; i++)

{

int temp = (int) (Math.random() * max);

if (!rand.contains(temp))

{

rand.add(temp);

}

else

{

i--;

}

}

return rand;

}

/** * 计算测试元组与训练元组之前的距离 * @param d1 测试元组* @param d2 训练元组 * @return 距离值 */

public double calDistance(List<Double> d1, List<Double> d2)

{

double distance = 0.00;

for (int i = 0; i < d1.size(); i++)

{

distance += (d1.get(i) - d2.get(i)) * (d1.get(i) - d2.get(i)); }

return distance;

}

/** * 执行KNN算法,获取测试元组的类别 * @param datas 训练数据集 * @param

testData 测试元组 * @param k 设定的K值 * @return 测试元组的类别 */

public String knn(List<List<Double>> datas, List<Double> testData, int k) {

PriorityQueue<KNNNode> pq = new PriorityQueue<KNNNode>(k,comparator); List<Integer> randNum = getRandKNum(k, datas.size());

for (int i = 0; i < k; i++)

{

int index = randNum.get(i);

List<Double> currData = datas.get(index);

String c = currData.get(currData.size()-1).toString();

KNNNode node = new KNNNode(index, calDistance(testData, currData), c); pq.add(node);

}

for (int i = 0; i < datas.size(); i++)

{

List<Double> t = datas.get(i);

double distance = calDistance(testData, t);

KNNNode top = pq.peek();

if (top.getDistance() > distance)

{

pq.remove();

pq.add(new KNNNode(i, distance, t.get(t.size()-1).toString())); }

}

return getMostClass(pq);

}

/** * 获取所得到的k个最近邻元组的多数类 * @param pq 存储k个最近近邻元组的优先级队列* @return 多数类的名称 */

private String getMostClass(PriorityQueue<KNNNode> pq)

{

Map<String, Integer> classCount = new HashMap<String, Integer>(); int pqsize = pq.size();

for (int i = 0; i < pqsize; i++)

{

KNNNode node = pq.remove();

String c = node.getC();

if (classCount.containsKey(c))

{

classCount.put(c, classCount.get(c) + 1);

}

else

{

classCount.put(c, 1);

}

}

int maxIndex = -1;

int maxCount = 0;

Object[] classes = classCount.keySet().toArray(); for (int i = 0; i < classes.length; i++)

{

if (classCount.get(classes[i]) > maxCount)

{

maxIndex = i; maxCount = classCount.get(classes[i]); }

}

return classes[maxIndex].toString();

}

}

//KNNNode.java

package cqu.KNN;

public class KNNNode

{

private int index; // 元组标号

private double distance; // 与测试元组的距离

private String c; // 所属类别

public KNNNode(int index, double distance, String c) {

super();

this.index = index;

this.distance = distance; this.c = c;

}

public int getIndex()

{

return index;

}

public void setIndex(int index)

{

this.index = index;

}

public double getDistance()

{

return distance;

}

public void setDistance(double distance)

{

this.distance = distance;

}

public String getC()

{

return c;

}

public void setC(String c)

{

this.c = c;

}

}

//TestKNN.java

package cqu.KNN;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.util.ArrayList;

import java.util.List;

// KNN算法测试类

public class TestKNN

{

/** * 从数据文件中读取数据 * @param datas 存储数据的集合对象 * @param path 数据文件的路径 */

public void read(List<List<Double>> datas, String path)

{

try {

BufferedReader br = new BufferedReader(new FileReader(new File(path))); String reader = br.readLine();

while (reader != null)

{

String t[] = reader.split(" ");

ArrayList<Double> list = new ArrayList<Double>();

for (int i = 0; i < t.length; i++)

{

list.add(Double.parseDouble(t[i]));

}

datas.add(list); reader = br.readLine();

}

}

catch (Exception e)

{

e.printStackTrace();

}

}

/** * 程序执行入口 * @param args */

public static void main(String[] args)

{

TestKNN t = new TestKNN();

String datafile = new File("").getAbsolutePath() + File.separator + "cqudata\\datafile.txt";

String testfile = new File("").getAbsolutePath() + File.separator + "cqudata\\testfile.txt";

try {

List<List<Double>> datas = new ArrayList<List<Double>>();

List<List<Double>> testDatas = new ArrayList<List<Double>>(); t.read(datas, datafile);

t.read(testDatas, testfile);

KNN knn = new KNN();

for (int i = 0; i < testDatas.size(); i++)

{

List<Double> test = testDatas.get(i);

System.out.print("测试元组: ");

for (int j = 0; j < test.size(); j++)

{

System.out.print(test.get(j) + " ");

}

System.out.print("类别为: ");

System.out.println(Math.round(Float.parseFloat((knn.knn(datas, test, 3)))));

}

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

五 运行测试

训练数据:

1.0 1.1 1.2 2.1 0.3 2.3 1.4 0.5 1

1.7 1.2 1.4 2.0 0.2 2.5 1.2 0.8 1

1.2 1.8 1.6 2.5 0.1 2.2 1.8 0.2 1

1.9 2.1 6.2 1.1 0.9 3.3 2.4 5.5 0

1.0 0.8 1.6 2.1 0.2 2.3 1.6 0.5 1

1.6 2.1 5.2 1.1 0.8 3.6 2.4 4.5 0

实验数据:

1.0 1.1 1.2 2.1 0.3 2.3 1.4 0.5

1.7 1.2 1.4 2.0 0.2 2.5 1.2 0.8

1.2 1.8 1.6 2.5 0.1 2.2 1.8 0.2

1.9 2.1 6.2 1.1 0.9 3.3 2.4 5.5

1.0 0.8 1.6 2.1 0.2 2.3 1.6 0.5

1.6 2.1 5.2 1.1 0.8 3.6 2.4 4.5

程序运行结果:

测试元组: 1.0 1.1 1.2 2.1 0.3 2.3 1.4 0.5 类别为: 1 测试元组: 1.7 1.2 1.4 2.0 0.2 2.5 1.2 0.8

测试元组: 1.2 1.8 1.6 2.5 0.1 2.2 1.8 0.2

测试元组: 1.9 2.1 6.2 1.1 0.9 3.3 2.4 5.5

测试元组: 1.0 0.8 1.6 2.1 0.2 2.3 1.6 0.5

测试元组: 1.6 2.1 5.2 1.1 0.8 3.6 2.4 4.5

类别为: 1 类别为: 1 类别为: 0 类别为: 1 类别为: 0

更多相关推荐:
算法实验报告

算法设计与分析实验报告班级姓名学号年月日目录实验一二分查找程序实现03页实验二棋盘覆盖问题分治法08页实验三01背包问题的动态规划算法设计11页实验四背包问题的贪心算法14页实验五最小重量机器设计问题回溯法17...

算法设计实验报告

算法设计课程报告课题名称算法设计与实现课题负责人名学号张樱紫0743111317同组成员名单角色无指导教师左劼评阅成绩评阅意见提交报告时间20xx年12月23日课程名称算法设计学生姓名张樱紫学生学号074311...

中南大学--算法实验报告

中南大学--算法实验报告,内容附图。

遗传算法实验报告

遗传算法实验报告姓名:**学号:**一、实验目的:熟悉和掌握遗传算法的运行机制和求解的基本方法。遗传算法是一种基于空间搜索的算法,它通过自然选择、遗传、变异等操作以及达尔文的适者生存的理论,模拟自然进化过程来寻…

算法设计实验报告

1hanoi塔packagesyyimportjavautilpublicclassHanoipublicstaticvoidmoveintnintaintbSystemoutprintlnquot把第quot...

算法实验报告

算法导论实验报告实验一快速排序1问题描述实现对数组的普通快速排序与随机快速排序2算法原理设要排序的数组是A0AN1首先选取一个数据普通快排选择的是最后一个元素随记快排是随机选择一个元素作为关键数据然后将所有比它...

算法分析与设计实验报告

排序问题求解实验日志实验题目排序问题求解实验目的1以排序分类问题为例掌握分治法的基本设计策略2熟练掌握一般插入排序算法的实现3熟练掌握快速排序算法的实现4理解常见的算法经验分析方法实验要求1生成实验数据要求编写...

算法综合性实验报告模板

综合性设计性实验报告姓名刘海香学号20xx08003107专业软件工程班级20xx级1班实验课程名称算法分析与设计指导教师及职称黎明讲师开课学期20xx至20xx学年下学期上课时间20xx年3月21日至20xx...

计算机算法与设计分析实验报告

计算机算法与设计分析实验报告班级姓名学号目录实验一分治与递归11基本递归算法12棋盘覆盖问题23二分搜索34实验小结5实验二动态规划算法51最长公共子序列问题52最大子段和问题73实验小结8实验三贪心算法81多...

算法实验报告

实验一分治与递归算法的应用一实验目的1掌握分治算法的基本思想分治合技巧和效率分析方法2熟练掌握用递归设计分治算法的基本步骤基准与递归方程3学会利用分治算法解决实际问题二实验内容金块问题老板有一袋金块共n块n是2...

图像Demosaic算法实验报告

图像Demosaic算法一马赛克成因一般的数码相机采用CDC或CMOS做传感器约占数码相机总成本的10一25是相机的最昂贵的部件之一quot对于专业相机如用在科学或医学中的使用了三个传感器每一个像素点都可以直接...

RSA算法的实现实验报告

RSA算法的实现一实验目的1熟悉公钥密码体制2掌握产生密钥对的程序设计方法3掌握产生加密解密的程序设计方法二实验内容和要求1进行RSA加密解密算法的设计2对RSA程序进行编译和调试3使用编写的程序进行加密和解密...

算法实验报告(32篇)