weka[11] - DBSCAN

来源:互联网 发布:淘宝反渗透膜 编辑:程序博客网 时间:2024/06/06 05:29

DBSCAN介绍可以看wiki:http://en.wikipedia.org/wiki/DBSCAN

从http://www.cnblogs.com/chaosimple/archive/2013/07/01/3164775.html 盗了个开头,作者原谅原谅啊。

1、DBSCAN简介

DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种基于密度的空间聚类算法。该算法将具有足够密度的区域划分为簇,并在具有噪声的空间数据库中发现任意形状的簇,它将簇定义为密度相连的点的最大集合。

该算法利用基于密度的聚类的概念,即要求聚类空间中的一定区域内所包含对象(点或其他空间对象)的数目不小于某一给定阈值。DBSCAN算法的显著优点是聚类速度快且能够有效处理噪声点和发现任意形状的空间聚类。但是由于它直接对整个数据库进行操作且进行聚类时使用了一个全局性的表征密度的参数,因此也具有两个比较明显的弱点:

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

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

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

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

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

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

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


直接看代码吧。

buildClustering:

    public void buildClusterer(Instances instances) throws Exception {        // can clusterer handle the data?        getCapabilities().testWithFail(instances);        long time_1 = System.currentTimeMillis();        processed_InstanceID = 0;        numberOfGeneratedClusters = 0;        clusterID = 0;        replaceMissingValues_Filter = new ReplaceMissingValues();        replaceMissingValues_Filter.setInputFormat(instances);        Instances filteredInstances = Filter.useFilter(instances, replaceMissingValues_Filter);        database = databaseForName(getDatabase_Type(), filteredInstances);        for (int i = 0; i < database.getInstances().numInstances(); i++) {            DataObject dataObject = dataObjectForName(getDatabase_distanceType(),                    database.getInstances().instance(i),                    Integer.toString(i),                    database);            database.insert(dataObject);        }        database.setMinMaxValues();
前面几行就是初始化以及处理missing。 然后把所有数据变成dataobject对象,放进database

        Iterator iterator = database.dataObjectIterator();        while (iterator.hasNext()) {            DataObject dataObject = (DataObject) iterator.next();            if (dataObject.getClusterLabel() == DataObject.UNCLASSIFIED) {                if (expandCluster(dataObject)) {                    clusterID++;                    numberOfGeneratedClusters++;                }            }        }        long time_2 = System.currentTimeMillis();        elapsedTime = (double) (time_2 - time_1) / 1000.0;   }
下面就是正式聚类了。iterator是database的迭代器,每次对新一个样本,如果该样本没有被分到某个簇,那么判断expandCluster(dataObject) ,如果为真,说明要产生新的簇了,所以clusterID和num_cluster要++。如果为假,说明这是个离群点,定义为NOISE。

下面看看expandCluster

   private boolean expandCluster(DataObject dataObject) {        List seedList = database.epsilonRangeQuery(getEpsilon(), dataObject);        /** dataObject is NO coreObject */        if (seedList.size() < getMinPoints()) {            dataObject.setClusterLabel(DataObject.NOISE);            return false;        }
epsilonRageQuery就是返回一个dataObject的领域内的点。如果点的数量小于阈值,那么不把它设定为中心。

        /** dataObject is coreObject */        for (int i = 0; i < seedList.size(); i++) {            DataObject seedListDataObject = (DataObject) seedList.get(i);            /** label this seedListDataObject with the current clusterID, because it is in epsilon-range */            seedListDataObject.setClusterLabel(clusterID);            if (seedListDataObject.equals(dataObject)) {                seedList.remove(i);                i--;            }        }
这一步的话就是给样本标记clusterID。然后把和dataobject相同的样本从list里面删去(为了下面继续扩充)

       for (int j = 0; j < seedList.size(); j++) {            DataObject seedListDataObject = (DataObject) seedList.get(j);            List seedListDataObject_Neighbourhood = database.epsilonRangeQuery(getEpsilon(), seedListDataObject);            /** seedListDataObject is coreObject */            if (seedListDataObject_Neighbourhood.size() >= getMinPoints()) {                for (int i = 0; i < seedListDataObject_Neighbourhood.size(); i++) {                    DataObject p = (DataObject) seedListDataObject_Neighbourhood.get(i);                    if (p.getClusterLabel() == DataObject.UNCLASSIFIED || p.getClusterLabel() == DataObject.NOISE) {                        if (p.getClusterLabel() == DataObject.UNCLASSIFIED) {                            seedList.add(p);                        }                        p.setClusterLabel(clusterID);                    }                }            }            seedList.remove(j);            j--;        }        return true;    }
下一步就是继续扩充啦。可以看到,如果以seedlist中的点为core,得到的新的list中,若list中的点没有clusterID,那么把这个点加入到seedList中,直到这类点完全被分离了。
这样整个DBSCAN就分析完了,还是挺好理解的。

0 0
原创粉丝点击