DBSCAN算法的Java实现

DBSCAN是一种基于密度的聚类算法,它的基本原理就是给定两个参数,ξ和minp,其中 ξ可以理解为半径,算法将在这个半径内查找样本,minp是一个以ξ为半径查找到的样本个数n的限制条件,只要n>=minp,查找到的样本点就是核心样本点,算法的具体描述见参考文件1,下边是这个算法的java实现:

  首先定义一个Point类,代表样本点

 

[java]  view plain  copy
  1. <!--[endif]-->  
  2.    
  3.   package com.sunzhenxing;  
  4.    
  5.   public class Point {  
  6.    
  7.   private int x;  
  8.    
  9.   private int y;  
  10.    
  11.   private boolean isKey;  
  12.    
  13.   private boolean isClassed;  
  14.    
  15.   public boolean isKey() {  
  16.    
  17.   return isKey;  
  18.    
  19.   }  
  20.    
  21.   public void setKey(boolean isKey) {  
  22.    
  23.   this.isKey = isKey;  
  24.    
  25.   this.isClassed=true;  
  26.    
  27.   }  
  28.    
  29.   public boolean isClassed() {  
  30.    
  31.   return isClassed;  
  32.    
  33.   }  
  34.    
  35.   public void setClassed(boolean isClassed) {  
  36.    
  37.   this.isClassed = isClassed;  
  38.    
  39.   }  
  40.    
  41.   public int getX() {  
  42.    
  43.   return x;  
  44.    
  45.   }  
  46.    
  47.   public void setX(int x) {  
  48.    
  49.   this.x = x;  
  50.    
  51.   }  
  52.    
  53.   public int getY() {  
  54.    
  55.   return y;  
  56.    
  57.   }  
  58.    
  59.   public void setY(int y) {  
  60.    
  61.   this.y = y;  
  62.    
  63.   }  
  64.    
  65.   public Point(){  
  66.    
  67.   x=0;  
  68.    
  69.   y=0;  
  70.    
  71.   }  
  72.    
  73.   public Point(int x,int y){  
  74.    
  75.   this.x=x;  
  76.    
  77.   this.y=y;  
  78.    
  79.   }  
  80.    
  81.   public Point(String str){  
  82.    
  83.   String[] p=str.split(",");  
  84.    
  85.   this.x=Integer.parseInt(p[0]);  
  86.    
  87.   this.y=Integer.parseInt(p[1]);  
  88.    
  89.   }  
  90.    
  91.   public String print(){  
  92.    
  93.   return "<"+this.x+","+this.y+">";  
  94.    
  95.   }  
  96.    
  97.   }  


然后定义一个工具类,为算法的实现服务:

[java]  view plain  copy
  1. package com.sunzhenxing;  
  2.    
  3.   import java.io.BufferedReader;  
  4.    
  5.   import java.io.FileReader;  
  6.    
  7.   import java.io.IOException;  
  8.    
  9.   import java.util.*;  
  10.    
  11.   public class Utility {  
  12.    
  13.   /** 
  14.   
  15.   * 测试两个点之间的距离 
  16.   
  17.   * @param p 点 
  18.   
  19.   * @param q 点 
  20.   
  21.   * @return 返回两个点之间的距离 
  22.   
  23.   */  
  24.    
  25.   public static double getDistance(Point p,Point q){  
  26.    
  27.   int dx=p.getX()-q.getX();  
  28.    
  29.   int dy=p.getY()-q.getY();  
  30.    
  31.   double distance=Math.sqrt(dx*dx+dy*dy);  
  32.    
  33.   return distance;  
  34.    
  35.   }  
[java]  view plain  copy
  1. <pre class="java" name="code">/** 
  2.   
  3.   * 检查给定点是不是核心点 
  4.   
  5.   * @param lst 存放点的链表 
  6.   
  7.   * @param p 待测试的点 
  8.   
  9.   * @param e e半径 
  10.   
  11.   * @param minp 密度阈值 
  12.   
  13.   * @return 暂时存放访问过的点 
  14.   
  15.   */  
  16.    
  17.   public static List<Point> isKeyPoint(List<Point> lst,Point p,int e,int minp){  
  18.    
  19.   int count=0;  
  20.    
  21.   List<Point> tmpLst=new ArrayList<Point>();  
  22.    
  23.   for(Iterator<Point> it=lst.iterator();it.hasNext();){  
  24.    
  25.   Point q=it.next();  
  26.    
  27.   if(getDistance(p,q)<=e){  
  28.    
  29.   ++count;  
  30.    
  31.   if(!tmpLst.contains(q)){  
  32.    
  33.   tmpLst.add(q);  
  34.    
  35.   }  
  36.    
  37.   }  
  38.    
  39.   }  
  40.    
  41.   if(count>=minp){  
  42.    
  43.   p.setKey(true);  
  44.    
  45.   return tmpLst;  
  46.    
  47.   }  
  48.    
  49.   return null;  
  50.    
  51.   }  
  52.    
  53.   public static void setListClassed(List<Point> lst){  
  54.    
  55.   for(Iterator<Point> it=lst.iterator();it.hasNext();){  
  56.    
  57.   Point p=it.next();  
  58.    
  59.   if(!p.isClassed()){  
  60.    
  61.   p.setClassed(true);  
  62.    
  63.   }  
  64.    
  65.   }  
  66.    
  67.   }  
  68.    
  69.   /** 
  70.   
  71.   * 如果b中含有a中包含的元素,则把两个集合合并 
  72.   
  73.   * @param a 
  74.   
  75.   * @param b 
  76.   
  77.   * @return a 
  78.   
  79.   */  
  80.    
  81.   public static boolean mergeList(List<Point> a,List<Point> b){  
  82.    
  83.   boolean merge=false;  
  84.    
  85.   for(int index=0;index<b.size();++index){  
  86.    
  87.   if(a.contains(b.get(index))){  
  88.    
  89.   merge=true;  
  90.    
  91.   break;  
  92.    
  93.   }  
  94.    
  95.   }  
  96.    
  97.   if(merge){  
  98.    
  99.   for(int index=0;index<b.size();++index){  
  100.    
  101.   if(!a.contains(b.get(index))){  
  102.    
  103.   a.add(b.get(index));  
  104.    
  105.   }  
  106.    
  107.   }  
  108.    
  109.   }  
  110.    
  111.   return merge;  
  112.    
  113.   }  
  114.    
  115.   /** 
  116.   
  117.   * 返回文本中的点集合 
  118.   
  119.   * @return 返回文本中点的集合 
  120.   
  121.   * @throws IOException 
  122.   
  123.   */  
  124.    
  125.   public static List<Point> getPointsList() throws IOException{  
  126.    
  127.   List<Point> lst=new ArrayList<Point>();  
  128.    
  129.   String txtPath="src\\com\\sunzhenxing\\points.txt";  
  130.    
  131.   BufferedReader br=new BufferedReader(new FileReader(txtPath));  
  132.    
  133.   String str="";  
  134.    
  135.   while((str=br.readLine())!=null && str!=""){  
  136.    
  137.   lst.add(new Point(str));  
  138.    
  139.   }  
  140.    
  141.   br.close();  
  142.    
  143.   return lst;  
  144.    
  145.   }  
  146.    
  147.   }  
  148. </pre>  
  149. <p><br>  
  150.  </p>  
  151. <pre></pre>  
  152. <p>最后在主程序中实现算法,如下所示:</p>  
  153. <pre class="java" name="code">package com.sunzhenxing;  
  154.    
  155.   import java.io.*;  
  156.    
  157.   import java.util.*;  
  158.    
  159.   public class Dbscan {  
  160.    
  161.   private static List<Point> pointsList=new ArrayList<Point>();//存储所有点的集合  
  162.    
  163.   private static List<List<Point>> resultList=new ArrayList<List<Point>>();//存储DBSCAN算法返回的结果集  
  164.    
  165.   private static int e=2;//e半径  
  166.    
  167.   private static int minp=3;//密度阈值  
  168.    
  169.   /** 
  170.   
  171.   * 提取文本中的的所有点并存储在pointsList中 
  172.   
  173.   * @throws IOException 
  174.   
  175.   */  
  176.    
  177.   private static void display(){  
  178.    
  179.   int index=1;  
  180.    
  181.   for(Iterator<List<Point>> it=resultList.iterator();it.hasNext();){  
  182.    
  183.   List<Point> lst=it.next();  
  184.    
  185.   if(lst.isEmpty()){  
  186.    
  187.   continue;  
  188.    
  189.   }  
  190. System.out.println("-----第"+index+"个聚类-----");  
  191.    
  192.   for(Iterator<Point> it1=lst.iterator();it1.hasNext();){  
  193.    
  194.   Point p=it1.next();  
  195.    
  196.   System.out.println(p.print());  
  197.    
  198.   }  
  199.    
  200.   index++;  
  201.    
  202.   }  
  203.    
  204.   }  
  205.    
  206.   //找出所有可以直达的聚类  
  207.    
  208.   private static void applyDbscan(){  
  209.    
  210.   try {  
  211.    
  212.   pointsList=Utility.getPointsList();  
  213.    
  214.   for(Iterator<Point> it=pointsList.iterator();it.hasNext();){  
  215.    
  216.   Point p=it.next();  
  217.    
  218.   if(!p.isClassed()){  
  219.    
  220.   List<Point> tmpLst=new ArrayList<Point>();  
  221.    
  222.   if((tmpLst=Utility.isKeyPoint(pointsList, p, e, minp)) != null){  
  223.    
  224.   //为所有聚类完毕的点做标示  
  225.    
  226.   Utility.setListClassed(tmpLst);  
  227.    
  228.   resultList.add(tmpLst);  
  229.    
  230.   }  
  231.    
  232.   }  
  233.    
  234.   }  
  235.    
  236.   } catch (IOException e) {  
  237.    
  238.   // TODO Auto-generated catch block  
  239.    
  240.   e.printStackTrace();  
  241.    
  242.   }  
  243.    
  244.   }  
  245.    
  246.   //对所有可以直达的聚类进行合并,即找出间接可达的点并进行合并  
  247.    
  248.   private static List<List<Point>> getResult(){  
  249.    
  250.   applyDbscan();//找到所有直达的聚类  
  251.    
  252.   int length=resultList.size();  
  253.    
  254.   for(int i=0;i<length;++i){  
  255.    
  256.   for(int j=i+1;j<length;++j){  
  257.    
  258.   if(Utility.mergeList(resultList.get(i), resultList.get(j))){  
  259.    
  260.   resultList.get(j).clear();  
  261.    
  262.   }  
  263.    
  264.   }  
  265.    
  266.   }  
  267.    
  268.   return resultList;  
  269.    
  270.   }  
  271.    
  272.   /** 
  273.   
  274.   * 程序主函数 
  275.   
  276.   * @param args 
  277.   
  278.   */  
  279.    
  280.   public static void main(String[] args) {  
  281.    
  282.   getResult();  
  283.    
  284.   display();  
  285.    
  286.   //System.out.println(Utility.getDistance(new Point(0,0), new Point(0,2)));  
  287.    
  288.   }  
  289.    
  290.   }  
  291. </pre>  
  292. <p><br>  
  293. 下边是一个小测试, 即使用src\\com\\sunzhenxing\\points.txt文件的内容进行测试,points.txt的文件内容是:</p>  
  294. <p>  0,0</p>  
  295. <p>  0,1</p>  
  296. <p>  0,2</p>  
  297. <p>  0,3</p>  
  298. <p>  0,4</p>  
  299. <p>  0,5</p>  
  300. <p>  12,1</p>  
  301. <p>  12,2</p>  
  302. <p>  12,3</p>  
  303. <p>  12,4</p>  
  304. <p>  12,5</p>  
  305. <p>  12,6</p>  
  306. <p>  0,6</p>  
  307. <p>  0,7</p>  
  308. <p>  12,7</p>  
  309. <p>  0,8</p>  
  310. <p>  0,9</p>  
  311. <p>  1,1</p>  
  312. <p>  最后算法的结果是:</p>  
  313. <p>  -----第1个聚类-----</p>  
  314. <p>  <0,0></p>  
  315. <p>  <0,1></p>  
  316. <p>  <0,2></p>  
  317. <p>  <1,1></p>  
  318. <p>  <0,3></p>  
  319. <p>  <0,4></p>  
  320. <p>  <0,5></p>  
  321. <p>  <0,6></p>  
  322. <p>  <0,7></p>  
  323. <p>  <0,8></p>  
  324. <p>  <0,9></p>  
  325. <p>  -----第2个聚类-----</p>  
  326. <p>  <12,1></p>  
  327. <p>  <12,2></p>  
  328. <p>  <12,3></p>  
  329. <p>  <12,4></p>  
  330. <p>  <12,5></p>  
  331. <p>  <12,6></p>  
  332. <p>  <12,7></p>  
  333. <p>  大家画一下坐标就可以理解实验的结论了。</p>  
  334. <p><br>  
  335.  </p>  
  336.      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值