转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/51064307

http://www.llwjy.com/blogdetail/f74b497c2ad6261b0ea651454b97a390.html

个人博客站已经上线了,网址 www.llwjy.com ~欢迎各位吐槽~

-------------------------------------------------------------------------------------------------

在開始之前先打一个小小的广告,自己创建一个QQ群:321903218,

_wv=1027&k=2K6A5e6">点击链接加入群【Lucene案例开发】,主要用于交流怎样使用Lucene来创建站内搜索后台,同一时候还会不定期的在群内开相关的公开课,感兴趣的童鞋能够加入交流。

KNN算法又叫近邻算法,是数据挖掘中一种经常使用的分类算法,接单的介绍KNN算法的核心思想就是:寻找与目标近期的K个个体,这些样本属于类别最多的那个类别就是目标的类别。比方K为7,那么我们就从数据中找到和目标近期(或者类似度最高)的7个样本,加入这7个样本相应的类别分别为A、B、C、A、A、A、B,那么目标属于的分类就是A(由于这7个样本中属于A类别的样本个数最多)。

算法实现

一、训练数据格式定义

以下就简单的介绍下怎样用JAVA来实现KNN分类,首先我们须要存储训练集(包含属性以及相应的类别),这里我们对未知的属性使用泛型。类别我们使用字符串存储。

 /**
*@Description: KNN分类模型中一条记录的存储格式
*/
package com.lulei.datamining.knn.bean; public class KnnValueBean<T>{
private T value;//记录值
private String typeId;//分类ID public KnnValueBean(T value, String typeId) {
this.value = value;
this.typeId = typeId;
} public T getValue() {
return value;
} public void setValue(T value) {
this.value = value;
} public String getTypeId() {
return typeId;
} public void setTypeId(String typeId) {
this.typeId = typeId;
}
}

二、K个近期邻类别数据格式定义

在统计得到K个近期邻中,我们须要记录前K个样本的分类以及相应的类似度,我们这里使用例如以下数据格式:

 /**
*@Description: K个近期邻的类别得分
*/
package com.lulei.datamining.knn.bean; public class KnnValueSort {
private String typeId;//分类ID
private double score;//该分类得分 public KnnValueSort(String typeId, double score) {
this.typeId = typeId;
this.score = score;
}
public String getTypeId() {
return typeId;
}
public void setTypeId(String typeId) {
this.typeId = typeId;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}

三、KNN算法基本属性

在KNN算法中,最重要的一个指标就是K的取值,因此我们在基类中须要设置一个属性K以及设置一个数组用于存储已知分类的数据。

private List<KnnValueBean> dataArray;
private int K = 3;

四、加入已知分类数据

在使用KNN分类之前,我们须要先向当中加入我们已知分类的数据。我们后面就是使用这些数据来预測未知数据的分类。

/**
* @param value
* @param typeId
* @Author:lulei
* @Description: 向模型中加入记录
*/
public void addRecord(T value, String typeId) {
if (dataArray == null) {
dataArray = new ArrayList<KnnValueBean>();
}
dataArray.add(new KnnValueBean<T>(value, typeId));
}

五、两个样本之间的类似度(或者距离)

在KNN算法中,最重要的一个方法就是怎样确定两个样本之间的类似度(或者距离)。由于这里我们使用的是泛型。并没有办法确定两个对象之间的类似度。一次这里我们把它设置为抽象方法,让子类来实现。这里我们方法定义为类似度,也就是返回值越大。两者越类似,之间的距离越短

/**
* @param o1
* @param o2
* @return
* @Author:lulei
* @Description: o1 o2之间的类似度
*/
public abstract double similarScore(T o1, T o2);

六、获取近期的K个样本的分类

KNN算法的核心思想就是找到近期的K个近邻,因此这一步也是整个算法的核心部分。

这里我们使用数组来保存类似度最大的K个样本的分类和类似度,在计算的过程中通过循环遍历全部的样本,数组保存截至当前计算点最类似的K个样本相应的类别和类似度。详细实现例如以下:

/**
* @param value
* @return
* @Author:lulei
* @Description: 获取距离近期的K个分类
*/
private KnnValueSort[] getKType(T value) {
int k = 0;
KnnValueSort[] topK = new KnnValueSort[K];
for (KnnValueBean<T> bean : dataArray) {
double score = similarScore(bean.getValue(), value);
if (k == 0) {
//数组中的记录个数为0是直接加入
topK[k] = new KnnValueSort(bean.getTypeId(), score);
k++;
} else {
if (!(k == K && score < topK[k -1].getScore())){
int i = 0;
//找到要插入的点
for (; i < k && score < topK[i].getScore(); i++);
int j = k - 1;
if (k < K) {
j = k;
k++;
}
for (; j > i; j--) {
topK[j] = topK[j - 1];
}
topK[i] = new KnnValueSort(bean.getTypeId(), score);
}
}
}
return topK;
}


七、统计K个样本出现次数最多的类别

这一步就是一个简单的计数,统计K个样本中出现次数最多的分类,该分类就是我们要预測的目标数据的分类。

/**
* @param value
* @return
* @Author:lulei
* @Description: KNN分类推断value的类别
*/
public String getTypeId(T value) {
KnnValueSort[] array = getKType(value);
HashMap<String, Integer> map = new HashMap<String, Integer>(K);
for (KnnValueSort bean : array) {
if (bean != null) {
if (map.containsKey(bean.getTypeId())) {
map.put(bean.getTypeId(), map.get(bean.getTypeId()) + 1);
} else {
map.put(bean.getTypeId(), 1);
}
}
}
String maxTypeId = null;
int maxCount = 0;
Iterator<Entry<String, Integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Integer> entry = iter.next();
if (maxCount < entry.getValue()) {
maxCount = entry.getValue();
maxTypeId = entry.getKey();
}
}
return maxTypeId;
}

到如今为止KNN分类的抽象基类已经编写完毕,在測试之前我们先多说几句,KNN分类是统计K个样本中出现次数最多的分类,这样的在有些情况下并非特别合理。比方K=5。前5个样本相应的分类分别为A、A、B、B、B。相应的类似度得分分别为10、9、2、2、1。假设使用上面的方法,那预測的分类就是B。可是看这些数据,预測的分类是A感觉更合理。基于这样的情况,自己对KNN算法提出例如以下优化(这里并不提供代码,仅仅提供简单的思路):在获取最类似K个样本和类似度后。能够对类似度和出现次数K做一种函数运算。比方加权。得到的函数值最大的分类就是目标的预測分类。

基类源代码

 /**
*@Description: KNN分类
*/
package com.lulei.datamining.knn; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry; import com.lulei.datamining.knn.bean.KnnValueBean;
import com.lulei.datamining.knn.bean.KnnValueSort;
import com.lulei.util.JsonUtil; @SuppressWarnings({"rawtypes"})
public abstract class KnnClassification<T> {
private List<KnnValueBean> dataArray;
private int K = 3; public int getK() {
return K;
}
public void setK(int K) {
if (K < 1) {
throw new IllegalArgumentException("K must greater than 0");
}
this.K = K;
} /**
* @param value
* @param typeId
* @Author:lulei
* @Description: 向模型中加入记录
*/
public void addRecord(T value, String typeId) {
if (dataArray == null) {
dataArray = new ArrayList<KnnValueBean>();
}
dataArray.add(new KnnValueBean<T>(value, typeId));
} /**
* @param value
* @return
* @Author:lulei
* @Description: KNN分类推断value的类别
*/
public String getTypeId(T value) {
KnnValueSort[] array = getKType(value);
System.out.println(JsonUtil.parseJson(array));
HashMap<String, Integer> map = new HashMap<String, Integer>(K);
for (KnnValueSort bean : array) {
if (bean != null) {
if (map.containsKey(bean.getTypeId())) {
map.put(bean.getTypeId(), map.get(bean.getTypeId()) + 1);
} else {
map.put(bean.getTypeId(), 1);
}
}
}
String maxTypeId = null;
int maxCount = 0;
Iterator<Entry<String, Integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Integer> entry = iter.next();
if (maxCount < entry.getValue()) {
maxCount = entry.getValue();
maxTypeId = entry.getKey();
}
}
return maxTypeId;
} /**
* @param value
* @return
* @Author:lulei
* @Description: 获取距离近期的K个分类
*/
private KnnValueSort[] getKType(T value) {
int k = 0;
KnnValueSort[] topK = new KnnValueSort[K];
for (KnnValueBean<T> bean : dataArray) {
double score = similarScore(bean.getValue(), value);
if (k == 0) {
//数组中的记录个数为0是直接加入
topK[k] = new KnnValueSort(bean.getTypeId(), score);
k++;
} else {
if (!(k == K && score < topK[k -1].getScore())){
int i = 0;
//找到要插入的点
for (; i < k && score < topK[i].getScore(); i++);
int j = k - 1;
if (k < K) {
j = k;
k++;
}
for (; j > i; j--) {
topK[j] = topK[j - 1];
}
topK[i] = new KnnValueSort(bean.getTypeId(), score);
}
}
}
return topK;
} /**
* @param o1
* @param o2
* @return
* @Author:lulei
* @Description: o1 o2之间的类似度
*/
public abstract double similarScore(T o1, T o2);
}

详细子类实现

对于上面介绍的都在KNN分类的抽象基类中,对于实际的问题我们须要继承基类并实现基类中的类似度抽象方法,这里我们做一个简单的实现。

 /**
*@Description:
*/
package com.lulei.datamining.knn.test; import com.lulei.datamining.knn.KnnClassification;
import com.lulei.util.JsonUtil; public class Test extends KnnClassification<Integer>{ @Override
public double similarScore(Integer o1, Integer o2) {
return -1 * Math.abs(o1 - o2);
} /**
* @param args
* @Author:lulei
* @Description:
*/
public static void main(String[] args) {
Test test = new Test();
for (int i = 1; i < 10; i++) {
test.addRecord(i, i > 5 ? "0" : "1");
}
System.out.println(JsonUtil.parseJson(test.getTypeId(0))); }
}

这里我们一共加入了1、2、3、4、5、6、7、8、9这9组数据,前5组的类别为1,后4组的类别为0。两个数据之间的类似度为两者之间的差值的绝对值的相反数,以下预測0应该属于的分类,这里K的默认值为3,因此近期的K个样本分别为1、2、3。相应的分类分别为"1"、"1"、"1",由于最后预測的分类为"1"。

-------------------------------------------------------------------------------------------------
小福利
-------------------------------------------------------------------------------------------------
      个人在极客学院上《Lucene案例开发》课程已经上线了。欢迎大家吐槽~

第一课:Lucene概述

第二课:Lucene 经常使用功能介绍

第三课:网络爬虫

第四课:数据库连接池

第五课:小说站点的採集

第六课:小说站点数据库操作

第七课:小说站点分布式爬虫的实现

第八课:Lucene实时搜索

JAVA实现KNN分类的更多相关文章

  1. knn分类算法学习

    K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一.该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的 ...

  2. KNN分类算法实现手写数字识别

    需求: 利用一个手写数字“先验数据”集,使用knn算法来实现对手写数字的自动识别: 先验数据(训练数据)集: ♦数据维度比较大,样本数比较多. ♦ 数据集包括数字0-9的手写体. ♦每个数字大约有20 ...

  3. KNN分类算法及python代码实现

    KNN分类算法(先验数据中就有类别之分,未知的数据会被归类为之前类别中的某一类!) 1.KNN介绍 K最近邻(k-Nearest Neighbor,KNN)分类算法是最简单的机器学习算法. 机器学习, ...

  4. 机器学习---K最近邻(k-Nearest Neighbour,KNN)分类算法

    K最近邻(k-Nearest Neighbour,KNN)分类算法 1.K最近邻(k-Nearest Neighbour,KNN) K最近邻(k-Nearest Neighbour,KNN)分类算法, ...

  5. (数据科学学习手札29)KNN分类的原理详解&Python与R实现

    一.简介 KNN(k-nearst neighbors,KNN)作为机器学习算法中的一种非常基本的算法,也正是因为其原理简单,被广泛应用于电影/音乐推荐等方面,即有些时候我们很难去建立确切的模型来描述 ...

  6. 在Ignite中使用k-最近邻(k-NN)分类算法

    在本系列前面的文章中,简单介绍了一下Ignite的线性回归算法,下面会尝试另一个机器学习算法,即k-最近邻(k-NN)分类.该算法基于对象k个最近邻中最常见的类来对对象进行分类,可用于确定类成员的关系 ...

  7. Python机器学习算法 — KNN分类

    KNN简介 K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一.KNN分类算法属于监督学习. 最简单最初级的分类器是将全部的训练 ...

  8. sklearn学习 第一篇:knn分类

    K临近分类是一种监督式的分类方法,首先根据已标记的数据对模型进行训练,然后根据模型对新的数据点进行预测,预测新数据点的标签(label),也就是该数据所属的分类. 一,kNN算法的逻辑 kNN算法的核 ...

  9. KNN分类算法

    K邻近算法.K最近邻算法.KNN算法(k-Nearest Neighbour algorithm):是数据挖掘分类技术中最简单的方法之一 KNN的工作原理 所谓K最近邻,就是k个最近的邻居的意思,说的 ...

随机推荐

  1. 寻找web根目录

    有时候,在利用一些命令执行漏洞时,可以以较高权限执行一些操作,但在我们想要上传shell的时候,却找不到网站根目录,下面是一些日常使用的寻找网站根目录的方法,记录下: 1.jsp 查看当前路径,在这个 ...

  2. ip地址正则表达式

    p = re.compile('^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$') if p.match(dom ...

  3. iOS之UITraitCollection

    UITraitCollection 为表征 size class 而生,用来区分设备.你可以在它身上获取到足以区分所有设备的特征. UITraitEnvironment 协议.UIContentCon ...

  4. 访问外网 ML2 的配置

    通过 router 可以实现位于不同 vlan 中的 instance 之间的通信. 接下来要探讨的问题是 instance 如何与外部网络通信. 这里的外部网络是指的租户网络以外的网络. 租户网络是 ...

  5. 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---37

    以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:

  6. vim 搜尋取代功能

    VI 的搜尋取代語法格式大致如下 :[範圍]s/[比對字串]/[取代字串]/[g,c,i] 範圍部分: 範圍表示法為開頭 , 結束 假如我要從第 1 行到第 150 行,可以這樣下: 1, 150 假 ...

  7. LeetCode OJ--Combinations *

    https://oj.leetcode.com/problems/combinations/ 给一个集合,求个数为k的所有子集 递归调用,深搜 class Solution { public: vec ...

  8. MQ 分拆Json数据包然后上传

    public void UploadInsurHistory() { using (IDbConnection connection = ConnConfig.DmsConnection) { IDb ...

  9. Linux系统日常运维-修改IP地址

    分享下高手写的很好的文章 IP地址.子网掩码.网络号.主机号.网络地址.主机地址 step 0: check the iptables.selinux service iptables iptable ...

  10. Android学习--持久化(一) 文件存储

    持久化之   文件存储 这里把Android持久化全都整理一下,这一篇文章先简单的说一下文件的存储,通过下面一个简单的Demo,理解一下这个文件存储,先说说下面Demo的思路: 1.创建EditTex ...