在ELKI中运行DBSCAN

时间:2014-05-13 14:50:10

标签: cluster-analysis data-mining weka dbscan elki

我正在尝试对一些地理空间数据进行聚类,之前我曾尝试使用WEKA库。 我找到了此benchmarking,并决定尝试ELKI

尽管建议使用ELKI作为Java库(假设维护不如UI),我将它合并到我的应用程序中,我可以说我很开心关于结果。它用于存储数据的结构远比Weka使用的结构更有效,并且它可以选择使用空间索引这一事实绝对是一个优势。

然而,当我将Weka's DBSCAN的结果与来自ELKI's DBSCAN的结果进行比较时,我有点疑惑。我会接受不同的实现可以给出略有不同的结果,但是这些差异使得我认为算法存在问题(可能是我的代码)。在两种算法中,簇的数量和它们的几何形状是非常不同的。

为了记录,我使用的是最新版本的ELKI(0.6.0),我用于模拟的参数是:

minpts = 50 小量= 0.008

我编写了两个DBSCAN函数(用于Weka和ELKI),其中"入口点"是带有点的csv,"输出"对于它们两者也是相同的:计算一组点的凹壳(每个簇一个)的函数。由于将csv文件读入ELKI"数据库"相对简单,我认为我的问题可能是:

a)在算法的参数化中; b)阅读结果(最有可能)。

参数化DBSCAN不会带来任何挑战,我使用了两个强制参数,我之前通过UI测试过:

ListParameterization params2 = new ListParameterization();
params2.addParameter(de.lmu.ifi.dbs.elki.algorithm.clustering.DBSCAN.Parameterizer.MINPTS_ID,        minPoints);
params2.addParameter(de.lmu.ifi.dbs.elki.algorithm.clustering.DBSCAN.Parameterizer.EPSILON_ID, epsilon);

阅读结果更具挑战性,因为我不完全理解存储集群的结构的组织;我的想法是遍历每个集群,获取点列表,并将其传递给计算凹壳的函数,以生成多边形。

    ArrayList<Clustering<?>> cs = ResultUtil.filterResults(result, Clustering.class);
    for (Clustering<?> c : cs) {
        System.out.println("clusters: " + c.getAllClusters().size());
      for (de.lmu.ifi.dbs.elki.data.Cluster<?> cluster : c.getAllClusters()) {
              if (!cluster.isNoise()){
                 Coordinate[] ptList=new Coordinate[cluster.size()];
                 int ct=0;
                    for (DBIDIter iter = cluster.getIDs().iter(); iter.valid(); iter.advance()) {
                        ptList[ct]=dataMap.get(DBIDUtil.toString(iter));
                        ++ct;
                    }                   
                //there are no "empty" clusters
                assertTrue(ptList.length>0);

                GeoPolygon poly=getBoundaryFromCoordinates(ptList);
                if (poly.getCoordinates().getGeometryType()==
                        "Polygon"){

                    try {
                        out.write(poly.coordinates.toText()+"\n");
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }           

                }else
                    System.out.println(
                            poly.getCoordinates().getGeometryType());

              }//!noise
      }
    }

我注意到&#34;噪音&#34;作为一个集群出现了,所以我忽略了这个集群(我不想画它)。 我不确定这是否是阅读群集的正确方法,因为我没有找到很多例子。我也有一些问题,但我还没有找到答案:

  • getAllClusters()和。之间的区别是什么? getTopLevelClusters()?
  • DBSCAN群集&#34;嵌套&#34;,即:我们可以得到点吗? 同时属于多个集群?为什么?
  • 我在某处读到我们不应该使用数据库ID来识别 这些要点与ELKI的内部使用一样,但还有其他方式 有获取每个群集中的点列表?我看了你 可以使用标签的关系,但我不知道如何实际 实现这个......

任何可能指向正确方向的评论,或任何代码建议迭代ELKI的DBSCAN结果集都会非常受欢迎!我在我的代码中也使用了ELKI的OPTICSxi,我对这些结果有甚至更多的问题,但我想我会将其保存到另一篇文章中。

2 个答案:

答案 0 :(得分:3)

这主要是@ Anony-Mousse的后续行动,他给出了一个非常完整的答案。

  • getTopLevelClusters()getAllClusters()对DBSCAN执行相同的操作,因为DBSCAN不会生成分层群集。
  • DBSCAN群集是不相交的。使用isNoise()==true作为单个对象处理聚类可能是处理噪声的最佳方法。我们的OPTICSXi实现返回的集群也是不相交的,但是您应该将所有子集群的成员视为外部集群的一部分。对于凸包,一种有效的方法是首先计算子群的凸包;然后为父母计算附加物体上的凸包+所有孩子的凸包点。
  • @ Anony-Mousse提到的RangeDBIDs方法对于静态数据库来说非常简洁。与动态数据库一起使用的干净方法是具有标识对象的附加关系。使用CSV文件作为输入时,您只需添加一个包含标签的非数字列,而不是依赖于行编号。 object123。从逻辑的角度来看,这是最好的方法 - 如果您希望能够识别对象,请为它们提供唯一的标识符。 ; - )
  • 我们使用ELKI进行教学,我们非常仔细地验证了它的DBSCAN算法(你可以找到DBSCAN step by step demonstration here,而且ELKI结果与此完全匹配)。 Weka中的DBSCAN和OPTICS代码是很久以前由学生提供的,并且从未经过同样的验证。 通过快速检查,Weka 在课堂练习数据集上生成正确的结果。
  • 因为练习数据集在每个维度上的相同扩展为10,我们可以将epsilon参数调整1/10,然后Weka结果似乎与解决方案匹配;所以@ Anony-Mousses的发现似乎是正确的:Weka的实现强制对数据进行[0; 1]缩放。

答案 1 :(得分:2)

如果你注意它们的分配方式,那么访问ELKI的DBIDs是有效的。

对于静态数据库,getDBIDs()将返回一个RangeDBIDs对象,它可以为您提供数据库的偏移量。这非常可靠。但是如果你总是重新开始你的过程,那么无论如何都会确定性地分配DBIDs(只有在使用MiniGUI时,如果你重新开始工作,它们会有所不同!)

这也比DBIDUtil.toString更有效。

DBSCAN结果不是分层结构,因此每个群集都应该是顶级群集。

至于Weka,它有时会自动标准化。那么epsilon值将会失真。对于地理数据,无论如何我更喜欢大地距离,纬度和经度上的欧几里德距离没有意义。

检查Wekas代码的这一部分:"norm" function, used by EuclideanDataObject。这个 看起来好像Wekas DBSCAN强制对数据集进行规范化!尝试将数据缩放到[0:1](我很确定在ELKI中有一个过滤器),如果之后结果相同吗?

从这段代码片段来看,我会责怪Weka。上面的代码对我来说也看起来有点低效。过滤器方法使IMHO比数据对象中的强制过滤更有意义。