聚类算法之DBScan(Java实现)

DBScan是一种基于密度的聚类算法,它有一个核心点的概念:如果一个点,在距它Eps的范围内有不少于MinPts个点,则该点就是核心点。核心和它Eps范围内的邻居形成一个簇。在一个簇内如果出现多个点都是核心点,则以这些核心点为中心的簇要合并。

下图给出DBScan的聚类结果:

 

 

可以看到DBScan可以发现噪声,即它把(3,14)判定为噪声。

到这里你一定有个疑问:为什么(8,3)一个点形成了一个簇,不是一个簇最少应该包含MinPts个点吗,如果只有一个点,那(8,3)应该归为噪声才对呀?

其实你仔细阅读下面的代码就会发现原因。在算法运行的早期,(8,3)(5,3)(8,6)(10,4)被划分为一个簇,并且此时判定(8,3)是核心点—这个决定不会再更改。只是到后来(5,3)(8,6)(10,4)又被划分到其他簇中去了。

下面给出DBScan算法的核心代码:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package  orisun;
 
import  java.io.File;
import  java.util.ArrayList;
import  java.util.Vector;
import  java.util.Iterator;
 
public  class  DBScan {
 
     double  Eps= 3 ;   //区域半径
     int  MinPts= 4 ;   //密度
     
     //由于自己到自己的距离是0,所以自己也是自己的neighbor
     public  Vector<DataObject> getNeighbors(DataObject p,ArrayList<DataObject> objects){
         Vector<DataObject> neighbors= new  Vector<DataObject>();
         Iterator<DataObject> iter=objects.iterator();
         while (iter.hasNext()){
             DataObject q=iter.next();
             double [] arr1=p.getVector();
             double [] arr2=q.getVector();
             int  len=arr1.length;
             
             if (Global.calEditDist(arr1,arr2,len)<=Eps){      //使用编辑距离
//          if(Global.calEuraDist(arr1, arr2, len)<=Eps){    //使用欧氏距离   
//          if(Global.calCityBlockDist(arr1, arr2, len)<=Eps){   //使用街区距离
//          if(Global.calSinDist(arr1, arr2, len)<=Eps){ //使用向量夹角的正弦
                 neighbors.add(q);
             }
         }
         return  neighbors;
     }
     
     public  int  dbscan(ArrayList<DataObject> objects){
         int  clusterID= 0 ;
         boolean  AllVisited= false ;
         while (!AllVisited){
             Iterator<DataObject> iter=objects.iterator();
             while (iter.hasNext()){
                 DataObject p=iter.next();
                 if (p.isVisited())
                     continue ;
                 AllVisited= false ;
                 p.setVisited( true );     //设为visited后就已经确定了它是核心点还是边界点
                 Vector<DataObject> neighbors=getNeighbors(p,objects);
                 if (neighbors.size()<MinPts){
                     if (p.getCid()<= 0 )
                         p.setCid(- 1 );       //cid初始为0,表示未分类;分类后设置为一个正数;设置为-1表示噪声。
                 } else {
                     if (p.getCid()<= 0 ){
                         clusterID++;
                         expandCluster(p,neighbors,clusterID,objects);
                     } else {
                         int  iid=p.getCid();
                         expandCluster(p,neighbors,iid,objects);
                     }
                 }
                 AllVisited= true ;
             }
         }
         return  clusterID;
     }
 
     private  void  expandCluster(DataObject p, Vector<DataObject> neighbors,
             int  clusterID,ArrayList<DataObject> objects) {
         p.setCid(clusterID);
         Iterator<DataObject> iter=neighbors.iterator();
         while (iter.hasNext()){
             DataObject q=iter.next();
             if (!q.isVisited()){
                 q.setVisited( true );
                 Vector<DataObject> qneighbors=getNeighbors(q,objects);
                 if (qneighbors.size()>=MinPts){
                     Iterator<DataObject> it=qneighbors.iterator();
                     while (it.hasNext()){
                         DataObject no=it.next();
                         if (no.getCid()<= 0 )
                             no.setCid(clusterID);
                     }
                 }
             }
             if (q.getCid()<= 0 ){       //q不是任何簇的成员
                 q.setCid(clusterID);
             }
         }
     }
 
     public  static  void  main(String[] args){
         DataSource datasource= new  DataSource();
         //Eps=3,MinPts=4
         datasource.readMatrix( new  File( "/home/orisun/test/dot.mat" ));
         datasource.readRLabel( new  File( "/home/orisun/test/dot.rlabel" ));
         //Eps=2.5,MinPts=4
//      datasource.readMatrix(new File("/home/orisun/text.normalized.mat"));
//      datasource.readRLabel(new File("/home/orisun/text.rlabel"));
         DBScan ds= new  DBScan();
         int  clunum=ds.dbscan(datasource.objects);
         datasource.printResult(datasource.objects,clunum);
     }
}
原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值