dbscan算法

dbscan算法是一种基于密度的聚类算法。

该算法的目的在于过滤低密度区域,发现稠密度样本点,跟传统的基于层次聚类和划分聚类的凸形聚类簇不同,该算法可以发现任意形状的聚类簇,与传统的算法相比它有如下优点:

      与K-means比较起来,你不必输入你要划分的聚类个数;

      聚类簇的形状没有bias;

      可以在需要时输入过滤噪声的参数;


DBSCAN中的的几个定义:

Ε领域:给定对象半径为Ε内的区域称为该对象的Ε领域

核心对象:如果给定对象Ε领域内的样本点数大于等于MinPts,则称该对象为核心对象

直接密度可达:对于样本集合D,如果样本点qpΕ领域内,并且p为核心对象,那么对象q从对象p直接密度可达

密度可达:对于样本集合D,给定一串样本点p1,p2….pnp= p1,q= pn,假如对象pipi-1直接密度可达,那么对象q从对象p密度可达

密度相连:对于样本集合D中的任意一点O,如果存在对象p到对象o密度可达,并且对象q到对象o密度可达,那么对象q到对象p密度相连

可以发现,密度可达是直接密度可达的传递闭包,并且这种关系是非对称的。密度相连是对称关系。DBSCAN目的是找到密度相连对象的最大集合。

Eg: 假设半径Ε=3MinPts=3,点pE领域中有点{m,p,p1,p2,o}, mE领域中有点{m,q,p,m1,m2},qE领域中有点{q,m},oE领域中有点{o,p,s},sE领域中有点{o,s,s1}.

那么核心对象有p,m,o,s(q不是核心对象,因为它对应的E领域中点数量等于2,小于MinPts=3)

m从点p直接密度可达,因为mpE领域内,并且p为核心对象;

q从点p密度可达,因为点q从点m直接密度可达,并且点m从点p直接密度可达;

q到点s密度相连,因为点q从点p密度可达,并且s从点p密度可达。


算法描述:

算法:DBSCAN

输入:E  半径

      MinPts  给定点在E领域内成为核心对象的最小领域点数

      D  集合

输出:目标类簇集合

方法:repeat

1)       判断输入点是否为核心对象

2)       找出核心对象的E领域中的所有直接密度可达点

      util 所有输入点都判断完毕

      repeat

         针对所有核心对象的E领域所有直接密度可达点找到最大密度相连对象集合,

         中间涉及到一些密度可达对象的合并。

      Util 所有核心对象的E领域都遍历完毕


优缺点:

DBSCAN算法的显著优点是聚类速度快且能够有效处理噪声点和发现任意形状的空间聚类。但是由于它直接对整个数据库进行操作且进行聚类时使用了一个全局性的表征密度的参数,因此也具有两个比较明显的弱点:

(1)当数据量增大时,要求较大的内存支持I/O消耗也很大;

(2)当空间聚类的密度不均匀、聚类间距差相差很大时,聚类质量较差。

2、DBSCAN和传统聚类算法对比

DBSCAN算法的目的在于过滤低密度区域,发现稠密度样本点。跟传统的基于层次的聚类和划分聚类的凸形聚类簇不同,该算法可以发现任意形状的聚类簇,与传统的算法相比它有如下优点:

(1)与K-MEANS比较起来,不需要输入要划分的聚类个数;

(2)聚类簇的形状没有偏倚;

(3)可以在需要时输入过滤噪声的参数;

R语言实现,来自fpc包中的例子:

<span style="font-size:18px;background-color: rgb(255, 255, 255);">install.packages("fpc")
library(fpc)

set.seed(665544)
n <- 600
x <- cbind(runif(10, 0, 10)+rnorm(n, sd=0.2), runif(10, 0, 10)+rnorm(n,sd=0.2))
ds <- dbscan(x, 0.2)
# run with showplot=1 to see how dbscan works.
ds
plot(ds, x)

x2 <- matrix(0,nrow=4,ncol=2)
x2[1,] <- c(5,2)
x2[2,] <- c(8,3)
x2[3,] <- c(5,8)
x2[4,] <- c(9,4)
predict(ds, x, x2)</span>


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);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值