我正在尝试对一些地理空间数据进行聚类,我之前尝试过 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,它们的“输出”也是相同的:一个计算一组点的凹 shell 的函数(每个集群一个)。由于将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
      }
    }

我注意到“噪音”是作为一个簇出现的,所以我忽略了这个簇(我不想画它)。
我不确定这是否是阅读集群的正确方法,因为我没有找到很多例子。我也有一些问题,我还没有找到答案:
  • getAllClusters() 和有什么区别
    获取TopLevelClusters()?
  • DBSCAN 集群是否“嵌套”,即:我们可以有点
    同时属于多个集群?为什么?
  • 我在某处读到我们不应该使用数据库 ID 来识别
    点,因为它们是供 ELKI 内部使用的,但还有什么其他方式
    有没有得到每个集群中的点列表?我读到你
    可以对标签使用关系,但我不确定如何实际使用
    实现这个...

  • 任何可以为我指明正确方向的评论,或者任何迭代 ELKI 的 DBSCAN 结果集的代码建议都将非常受欢迎!我还在我的代码中使用了 ELKI 的 OPTICSxi,关于这些结果我有 甚至更多 问题,但我想我会把它留到另一篇文章中。

    最佳答案

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

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

    这也将比 DBIDUtil.toString 更有效。

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

    至于 Weka,它有时会自动归一化。那么epsilon 值将被扭曲。对于地理数据,无论如何我更喜欢大地距离,纬度和经度的欧几里得距离没有意义。

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

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

    关于cluster-analysis - 在 ELKI 中运行 DBSCAN,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23634614/

    10-12 18:11