聚类相同大小的群集

时间:2018-05-18 10:07:01

标签: cluster-computing cluster-analysis k-means

我得到了一个X和Y点列表,它们映射了一个真实世界的位置。 我想要做的是,根据给定的点创建大小相同的簇。

我尝试基于k-means算法编写自己的实现,因为我无法理解或重新创建我在网上找到的任何示例。

我为每个群集的每个点创建一个(已排序的)距离列表。 每个点都被推送到堆栈,我将通过以下方式完成堆栈:

当堆栈不为空时

从堆栈中获取第一个点p(stack.pop)
对于从p到所有簇的所有距离
如果第一个(最近的)群集未满 - 将该点放入此群集中 其他(最近的群集已满)
在期望的簇中是否存在点dt,dst为期望的> p.dst to desired
是 - 删除pt并添加p,然后将pt添加到pointStack以重新计算pt
不 - 我在这做什么?

所以我所做的基本上是优化群集,使群集中所有点的总距离最小,而群集也有一定的最大点数。

代码:

  Stack<Point2D> pointsStack = new Stack<Point2D>();

  //Find distances for every Point to every cluster
  for (PT p : points) {
     List<Distance> pDsts = new ArrayList<Distance>();
     for (Cluster c : clusters) {
        Distance d = null;
        switch (dstFunction) {
           case EUKLID:
              d = new Distance(p, p.distanceFunc(c.x, c.y), c);
              break;
           case LINEAR:
              d = new Distance(p, p.geoDistanceFunc(c.x, c.y), c);
              break;
        }
        pDsts.add(d);
     }
     Collections.sort(pDsts);
     p.dstsToClusters = pDsts;
     pointsStack.push(p);
  }

  //For all points in the pointStack
  while (!pointsStack.isEmpty()) {
     Point2D p = pointsStack.pop();
     //for all distances from p to all clusters
     for (Distance d : p.dstsToClusters) {
        boolean foundSwap = false;
        if (d.cluster.size() < maxSizeCluster) {
           d.cluster.addPoint(p);
           break;
        } else { //this cluster is full
           //Is there a point pt in the desired cluster with dst to desired > p.dst to desired
           //Yes - remove pt and add p, then add pt to the pointStack to recompute pt; No - find another cluster
           for (Point2D pt : d.cluster.points) {//for ever point in the desired cluster 
              for (Distance dpt : pt.dstsToClusters) {//for every distance in every point in the desired cluster
                 //find a point in the desired cluster with dst < than p.dst to desired
                 if (dpt.cluster.clusterNumber() == d.cluster.clusterNumber() && d.dstToCluster < dpt.dstToCluster) {
                    d.cluster.addPoint(p);
                    d.cluster.removePoint(pt);

                    pointsStack.push(pt);
                    foundSwap = true;
                    break;
                 }
              }
              if (foundSwap) {
                 break;
              }
           }
        }
        if (foundSwap) {
           break;
        }
        //ELSE -> All points are closer to cluster center than the one that 
        //wants to get into this cluster, so the point will be assigned to 
        //another cluster.
     }
  }

我的结果非常令人满意,而且大部分时间都是我想要的,但在某些情况下,如果一个点想要交换到一个集群,那么结果将不会做任何事情,但该集群已经满了,没有任何意义比现在更远。因此,这一点将被置于第二个最佳集群中,如果相同(没有比集群比电流更远的点)再次发生,则甚至可以放入第三个集群。你可以在这张图片中清楚地看到这一点:IMAGE布鲁斯周围的粉红色/玫瑰点真的没有意义,它(我会说的)&#34;坏&#34;群集。

有人可以建议如何解决这个问题吗?

再次..这些形成发生是因为蓝色群集已经满了。然后其中一个粉红色/玫瑰点(此刻实际上没有任何颜色,但只是称它们为粉红色/玫瑰点)想要进入蓝色星团,因为它是所有周围最近的星团。但是,蓝色星团中没有一个点与群集中心的距离比想要进入蓝色群集的粉红色/玫瑰点的距离更大。因此粉红色/玫瑰点被分配到具有第二最佳距离的下一个最佳聚类(在这种情况下为橙色或青色)。不幸的是,尝试插入这两个集群会导致同样的问题。现在,粉红色/玫瑰点将被分配到第四个最佳聚类 - 粉红色/玫瑰色聚类。这意味着群集将围绕其他群集增长,这是我不想要的。

我想到的解决方案是,将粉红色/玫瑰点与蓝色星团中的一些点交换 - 最好是与最接近另一个星团的点(不应该是满的[最好是交换点的第二个最佳集群]),以便蓝色集群&#34;增长&#34;稍微偏向左下方,以至于所有的粉红色/玫瑰点都在蓝色星团中,粉红色/玫瑰色的星团会稍微大一些,也会略微重新定向。但是我目前还不知道如何实现这个逻辑。

1 个答案:

答案 0 :(得分:0)

有这样一个算法的详细教程&amp; ELKI中的示例实现:

https://elki-project.github.io/tutorial/same-size_k_means

它讨论了如果无法将点分配到最近的群集,如何进一步改善结果。