现在的位置: 首页 > 综合 > 正文

DBSCAN算法的java实现

2012年06月23日 ⁄ 综合 ⁄ 共 4680字 ⁄ 字号 评论关闭

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) is a data clustering algorithm proposed by Martin Ester, Hans-Peter Kriegel, Jörg Sander and Xiaowei Xu in 1996. It is a density based clustering algorithm because it finds a number of clusters starting from the estimated density distribution of corresponding nodes. DBSCAN is one of the most common clustering algorithms and also most cited in scientific literature.

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

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

  1: package com.sunzhenxing;
  2: 
  3: public class Point {
  4:   private int x;
  5:   private int y;
  6:   private boolean isKey;
  7:   private boolean isClassed;
  8:   
  9:   public boolean isKey() {
 10:     return isKey;
 11:   }
 12:   public void setKey(boolean isKey) {
 13:     this.isKey = isKey;
 14:     this.isClassed=true;
 15:   }
 16:   public boolean isClassed() {
 17:     return isClassed;
 18:   }
 19:   public void setClassed(boolean isClassed) {
 20:     this.isClassed = isClassed;
 21:   }
 22:   public int getX() {
 23:     return x;
 24:   }
 25:   public void setX(int x) {
 26:     this.x = x;
 27:   }
 28:   public int getY() {
 29:     return y;
 30:   }
 31:   public void setY(int y) {
 32:     this.y = y;
 33:   }
 34:   
 35:   public Point(){
 36:     x=0;
 37:     y=0;
 38:   }
 39:   public Point(int x,int y){
 40:     this.x=x;
 41:     this.y=y;
 42:   }
 43:   public Point(String str){
 44:     String[] p=str.split(",");
 45:     this.x=Integer.parseInt(p[0]);
 46:     this.y=Integer.parseInt(p[1]);
 47:   }
 48:   public String print(){
 49:     return "<"+this.x+","+this.y+">";
 50:   }
 51: }
 52: 

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

  1: package com.sunzhenxing;
  2: 
  3: import java.io.BufferedReader;
  4: import java.io.FileReader;
  5: import java.io.IOException;
  6: import java.util.*;
  7: 
  8: public final class Utility {
  9:   //计算两点之间的距离
 10:   public static double getDistance(Point p,Point q){
 11:     int dx=p.getX()-q.getX();
 12:     int dy=p.getY()-q.getY();
 13:     double distance=Math.sqrt(dx*dx+dy*dy);
 14:     return distance;
 15:   }
 16:   //检测p点是不是核心点,tmpLst存储核心点的直达点
 17:   public static List<Point> isKeyPoint(List<Point> lst,Point p,int e,int minp){
 18:     int count=0;
 19:     List<Point> tmpLst=new ArrayList<Point>();
 20:     for(Iterator<Point> it=lst.iterator();it.hasNext();){
 21:       Point q=it.next();
 22:       if(getDistance(p,q)<=e){
 23:         ++count;
 24:         if(!tmpLst.contains(q)){
 25:           tmpLst.add(q);
 26:         }
 27:       }
 28:     }
 29:     if(count>=minp){
 30:       p.setKey(true);
 31:       return tmpLst;
 32:     }
 33:     return null;
 34:   }
 35:   //合并两个链表,前提是b中的核心点包含在a中
 36:   public static boolean mergeList(List<Point> a,List<Point> b){
 37:     boolean merge=false;
 38:     if(a==null || b==null){
 39:       return false;
 40:     }
 41:     for(int index=0;index<b.size();++index){
 42:       Point p=b.get(index);
 43:       if(p.isKey() && a.contains(p)){
 44:         merge=true;
 45:         break;
 46:       }
 47:     }
 48:     if(merge){
 49:       for(int index=0;index<b.size();++index){
 50:         if(!a.contains(b.get(index))){
 51:           a.add(b.get(index));
 52:         }
 53:       }
 54:     }
 55:     return merge;
 56:   }
 57:   //获取文本中的样本点集合
 58:   public static List<Point> getPointsList() throws IOException{
 59:     List<Point> lst=new ArrayList<Point>();
 60:     String txtPath="src\\com\\sunzhenxing\\points.txt";
 61:     BufferedReader br=new BufferedReader(new FileReader(txtPath));
 62:     String str="";
 63:     while((str=br.readLine())!=null && str!=""){
 64:       lst.add(new Point(str));
 65:     }
 66:     br.close();
 67:     return lst;
 68:   }
 69:   //显示聚类的结果
 70:   public static void display(List<List<Point>> resultList){
 71:     int index=1;
 72:     for(Iterator<List<Point>> it=resultList.iterator();it.hasNext();){
 73:       List<Point> lst=it.next();
 74:       if(lst.isEmpty()){
 75:         continue;
 76:       }
 77:       System.out.println("-----第"+index+"个聚类-----");
 78:       for(Iterator<Point> it1=lst.iterator();it1.hasNext();){
 79:         Point p=it1.next();
 80:         System.out.println(p.print());
 81:       }
 82:       index++;
 83:     }
 84:   }
 85: }
 86: 

最后在主程序中实现算法,如下所示:

  1: package com.sunzhenxing;
  2: 
  3: import java.io.IOException;
  4: import java.util.*;
  5: 
  6: public class Dbscan {
  7:   private final static int e=2;//ε半径
  8:   private final static int minp=4;//密度阈值
  9:   private static List<Point> pointsList=new ArrayList<Point>();//存储原始样本点
 10:   private static List<List<Point>> resultList=new ArrayList<List<Point>>();//存储最后的聚类结果
 11:   
 12:   private static void applyDbscan() throws IOException{
 13:     pointsList=Utility.getPointsList();
 14:     for(int index=0;index<pointsList.size();++index){
 15:       List<Point> tmpLst=new ArrayList<Point>();
 16:       Point p=pointsList.get(index);
 17:       if(p.isClassed())
 18:         continue;
 19:       tmpLst=Utility.isKeyPoint(pointsList, p, e, minp);
 20:       if(tmpLst!=null){
 21:         resultList.add(tmpLst);
 22:       }
 23:     }
 24:     int length=resultList.size();
 25:     for(int i=0;i<length;++i){
 26:       for(int j=0;j<length;++j){
 27:         if(i!=j){
 28:           if(Utility.mergeList(resultList.get(i), resultList.get(j))){
 29:             resultList.get(j).clear();
 30:           }
 31:         }
 32:       }
 33:     }
 34:   }
 35:   public static void main(String[] args) {
 36:     try {
 37:       //调用DBSCAN的实现算法
 38:       applyDbscan();
 39:       Utility.display(resultList);
 40:     } catch (IOException e) {
 41:       // TODO Auto-generated catch block
 42:       e.printStackTrace();
 43:     }
 44:     
 45:   }
 46: 
 47: }
 48: 

下边是一个小测试, 即使用src\\com\\sunzhenxing\\points.txt文件的内容进行测试,points.txt的文件内容是:

0,0
0,1
0,2
0,3
0,4
0,5
12,1
12,2
12,3
12,4
12,5
12,6
0,6
0,7
12,7
0,8
0,9
1,1

最后算法的结果是:

-----第1个聚类-----
<0,0>
<0,1>
<0,2>
<1,1>
<0,3>
<0,4>
<0,5>
<0,6>
<0,7>
<0,8>
<0,9>
-----第2个聚类-----
<12,1>
<12,2>
<12,3>
<12,4>
<12,5>
<12,6>
<12,7>
大家画一下坐标就可以理解实验的结论了。

抱歉!评论已关闭.