本站首页    管理页面    写新日志    退出

公告

宿命宽恕轮回修仙


我的分类(专题)

日志更新

最新评论

留言板

链接

-----------数据挖掘-----------

Data Mining Community's Top Resource(KDnuggets)
Information Management(DMReview)
STATISTICA Software(StatSoft)
IIR USA(CRM Community)
Editor's Picks(CustomerThink)
Data Mining Group
ACM SIGKDD(DM顶级国际会议)
SourceForge.NET(Open Source Software)

SAS
SPSS
KXEN
WEKA
AlphaMiner
RapidMiner

中国万维网联盟(W3CHINA)
中国统计网
数据库专委会
数据挖掘研究院(China Data Mining Research)
LAMDA机器学习与数据挖掘研究组
北京大学计算语言学研究所
北京大学Dlib组
哈工大信息检索研究室论坛
神威学术资源中心

CRMSKY
数据挖掘学习交流论坛
计算机科学论坛
数据分析论坛
Weka中文站
R语言中文论坛
SAS中文论坛

ECT 584

-----------同行博客-----------

数据挖掘者(IDMer)
数据挖掘青年(DMman)
数据挖掘斗士(DMFighter)
神威异度空间
一维空间
不准阁
不断学习
欧燊怡
Datamining&BI
王义
Koala++

-----------学者信息-----------

Jiawei Han(韩家炜)
张鹏
曾元顯
吴俊杰

-----------回忆过去-----------

www.5im.cn
www.ustbhrm.com
www.finance3399.cn
www.xueyuanlu.cn
www.ccesr.com
econometrics.buaa.edu.cn

 


Blog信息
blog名称:宿命宽恕轮回修仙
日志总数:18
评论数量:3
留言数量:0
访问次数:114700
建立时间:2009年3月18日

«September 2025»
123456
78910111213
14151617181920
21222324252627
282930




[WEKA](转)对Weka中DBSCAN算法的分析以及在C#中的实现
文章收藏,  软件技术

宿命宽恕轮回修仙 发表于 2009/6/5 19:14:47

  DBSCAN算法是常用的数据挖掘算法。所有的聚类方法分为若干类型,前面讨论过的KMEANS算法是基于划分的方法进行聚类,而这次提到的DBSCAN算法是基于密度的方法。当然其它的还有基于层次凝聚和分裂的方法、基于模型的方法等。我先对Weka中实现的DBSCAN算法进行一个介绍和分析,然后再分析自己用C#实现的DBSCAN方法。但在这之前要解释几个概念,如果之前没有了解过这个算法的话,最好是先熟悉几个概念:epsilon-邻域、核心对象、(直接)密度可达、密度相连,这些概念可以在《数据挖掘概念与技术》一书中找到,了解这些概念对理解这个算法来说是很重要的。   我们先来看看在Weka中是如何实现DBSCAN算法的:   DBSCAN算法的源代码在Weka的weka.clusterers这个包中,文件名为DBScan.java。其中buildClusterer和expandCluster这两个方法是最核心的方法。buildClusterer是所有聚类方法的接口方法,而expandCluster是用于扩展样本对象集合的高密度连接区域的。另外还有一个叫epsilonRangeQuery的方法,这个方法位置Database类中,用于查询指定对象在epsilon邻域内的样本对象集合。   在buildClusterer方法中,通过对每个未聚类的样本点调用expandCluster方法进行处理,查找由这个对象开始的密度相连的最大样本对象集合。在这个方法中处理的主要代码如下,当expandCluster方法返回真的时候就说明一个簇已经形成,取下一个聚类标号。 Weka.DBSCANwhile (iterator.hasNext()) {    DataObject dataObject = (DataObject) iterator.next();    if (dataObject.getClusterLabel() == DataObject.UNCLASSIFIED) {        if (expandCluster(dataObject)) {            clusterID++;            numberOfGeneratedClusters++;         }    }}   buildClusterer方法中的代码比较简单,主要是提供一个处理入口。下面再来看expandCluster方法,这个方法要接收一个样本对象作为参数。在这个方法主要干几件事情:判断这个样本对象是不是核心对象,如果是核心对象再判断这个样本对象的epsilon邻域中的每一个对象,检查它们是不是核心对象,如果是核心对象则将其合并到当前的聚类中。源代码分析如下: Weka.DBSCAN//查找dataObject这个样本对象的epsilon邻域中的所有样本对象并将其存放到一个列表中,这个列表用于存放在密度区域过程扩展中欲处理的样本对象,后面还会用到这个列表List seedList = database.epsilonRangeQuery(getEpsilon(), dataObject);//判断dataObject是不是核心对象if (seedList.size() < getMinPoints()) {  //如果不是核心对象则将其设置为噪声点  dataObject.setClusterLabel(DataObject.NOISE);  //将其设置为噪声点后要返回false以防止聚类编号的增加  return false;}//如果样本对象dataObject是核心对象,则对其邻域中的每一个对象进行处理for (int i = 0; i < seedList.size(); i++) {  DataObject seedListDataObject = (DataObject) seedList.get(i);    //设置dataObject邻域中的每个样本对象的聚类标识,将其归为一个簇  seedListDataObject.setClusterLabel(clusterID);    //如果邻域中的样本对象与当前这个dataObject是同一个对象那么将其删除,如果在这里不做这个处理将会引起死循环  if (seedListDataObject.equals(dataObject)) {       seedList.remove(i);    i--;  }}  //对dataObject的epsilon邻域中的每一个样本对象进行处理  for (int j = 0; j < seedList.size(); j++) {        //从邻域中取出一个样本对象seedListDataObject    DataObject seedListDataObject = (DataObject) seedList.get(j);      //查找seedListDataObject的epsilon邻域并取得其中所有的样本对象    List seedListDataObject_Neighbourhood = database.epsilonRangeQuery(getEpsilon(), seedListDataObject);    //判断seedListDataObject是不是核心对象    if (seedListDataObject_Neighbourhood.size() >= getMinPoints()) {      for (int i = 0; i < seedListDataObject_Neighbourhood.size(); i++){        DataObject p = (DataObject) seedListDataObject_Neighbourhood.get(i);        //如果seedListDataObject样本对象是一个核心对象则将这个样本对象邻域中的所有未被聚类的对象添加到seedList中        //并且设置其中未聚类对象或噪声对象的聚类标号为当前聚类标号        if (p.getClusterLabel() == DataObject.UNCLASSIFIED || p.getClusterLabel() == DataObject.NOISE) {          if (p.getClusterLabel() == DataObject.UNCLASSIFIED) {          //在这里将样本对象添加到seedList列表中的做法是一种广度优先的方法,通过这种方法来逐步扩展当前聚类。          //这是非常重要的一条语句。如果没有这句就不能形成扩展的查找趋势,不能找到一个完全的密度连接区域。          seedList.add(p);        }        p.setClusterLabel(clusterID);      }    }  }  //去除当前处理的样本点,其目的与前面一样,为了避免死循环  seedList.remove(j);  j--;}//查找到一个完整的密度连接区域后,返回真完成处理return true;   上面分析了Weka中DBSCAN算法的执行流程,接下来就是C#版本的DBSCAN算法。C#的实现与Weka中的版本有一些区别。在上面的注释中已经提到过,Weka中的DBSCAN是以广度优先的方法来进行密度连接区域的扩展的,而在本文所提到的C#版本的DBSCAN算法是采用递归的方式以深度优先的方式进行密度连接区域的扩展。下面还是通过代码注释的方式进行分析,在分析之前先对几个自定义类型说明一下:   ClusterSample——用于表示样本对象的类   SampleStatus——用于表示样本对象状态的类,包含Unclassfied,Classfied,Noise三个枚举值   SampleCollection——用于表示样本集合的类,iCollection就是这个类的一个实例   代码分析: C#.DBSCANfor (int i = 0; i < iCollection.Count; i++){    ClusterSample sample = iCollection[i] as ClusterSample;    if (sample != null && sample.Status == SampleStatus.Unclassfied)    {        RangeExpand(sample);        //完成一个簇的扩展后更改聚类标号        if (sample.Status == SampleStatus.Classfied)        {            K++;        }    }} CodeIList<ClusterSample> epslionNeighborSamples = new List<ClusterSample>();    epslionNeighborSamples = FindNeighborObjects(currSample);currSample.ClusterID = K;//如果大于iMinPts值则为核心对象(此判断也是递归的结束条件)//移除当前样本点否则会造成无限递归,导致溢出epslionNeighborSamples.Remove(currSample);if (epslionNeighborSamples.Count >= iMinPts){    foreach (ClusterSample item in epslionNeighborSamples)    {        //对于currSample邻域中的每一个样本,检查其是否也是核心对象        //如果是核心对象那么从currSample到这个点是直接密度可达的。并且这两个对象之间就是密度相连的        //如果不满足这一点,从currSample到item这个点就不是密度相连的,这个点也就不属于当前密度连接区域        IList<ClusterSample> item_neighbours = FindNeighborObjects(item);        if (item_neighbours.Count >= iMinPts)        {            if (item.Status == SampleStatus.Unclassfied || item.Status == SampleStatus.Noise)            {                item.ClusterID = K;                    //递归地查找密度可达的样本对象                RangeExpand(item);            }        }    }    epslionNeighborSamples.Clear();}else{    currSample.Status = SampleStatus.Noise;}   C#版本的DBSCAN算法的递归实现源于对样本集合分布形态的考虑,即对密度连接区域的搜索扩展总会收敛到某个对象,这个对象的邻域所包含的对象个数不大于参数所指定的个数,那么这个对象就是密度区域的结束位置,这时一轮递归处理结束。当对所有邻域中的对象进行了递归处理后,一个簇的生成就完成了,接着再进行下一个簇的生成,以此类推……   DBSCAN的执行过程是一个簇区域不断扩张的过程,所以与KMEANS不同(KMEANS对噪声数据非常敏感,也就是说KMEANS算法可能会因为噪声点而影响其计算结果),DBSCAN可以发现任意形状的聚类,并且可以发现样本集合中的噪声。在DBSCAN中没有被包含在任何簇中的样本对象就是噪声对象。


阅读全文(2272) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.031 second(s), page refreshed 144765731 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号