我用 Java 编写了一个低效但简单的算法,看看我可以多接近在一组点上进行一些基本的聚类,或多或少如问题中所述。
ps如果 (x,y) 坐标指定为ints ,则该算法适用于列表。它还需要三个其他参数:
- radius (
r): 给定一个点,扫描附近点的半径是多少
- 最大地址(
maxA):每个集群的最大地址(点)数是多少?
- 最小地址 (
minA):每个集群的最小地址
设置limitA=maxA。
主迭代:
初始化空列表possibleSolutions。
外部迭代:对于p. ps初始化空列表pclusters。定义了一个点的工作清单wps=copy(ps)。工作点wp=p。
内部迭代: whilewps不为空。删除 中的点wp。wps确定距离 < fromwpsInRadius的所有点。根据与 的距离升序排列。将第一点保留在. 这些点形成一个新的集群(点列表)。添加到. 从中删除点。如果wpsrwpwpsInRadiuswpmin(limitA, sizeOf(wpsInRadius))wpsInRadiuspclusterpclusterpclusterspclusterwpswps不为空,wp=wps[0]继续内迭代。
结束内部迭代。
获得集群列表pclusters。将此添加到possibleSolutions.
结束外部迭代。
我们有一个集群列表中的p每一个。然后每一个都被加权。如果是(全局)中每个簇的平均点数,并且是每个(全局)中的平均簇数,那么这是使用这两个变量来确定权重的函数:pspclusterspossibleSolutionspclustersavgPCpossibleSolutionsavgCSizepclusters
private static WeightedPClusters weigh(List<Cluster> pclusters, double avgPC, double avgCSize)
{
double weight = 0;
for (Cluster cluster : pclusters)
{
int ps = cluster.getPoints().size();
double psAvgPC = ps - avgPC;
weight += psAvgPC * psAvgPC / avgCSize;
weight += cluster.getSurface() / ps;
}
return new WeightedPClusters(pclusters, weight);
}
现在最好的解决方案是pclusters重量最小的。只要我们能找到比之前最好的解决方案更好的解决方案(权重更小),我们就会重复主迭代limitA=max(minA,(int)avgPC)。结束主迭代。
请注意,对于相同的输入数据,此算法将始终产生相同的结果。列表用于保持顺序,不涉及随机。
要查看该算法的行为方式,这是 32 点测试模式上的结果图像。如果maxA=minA=16,那么我们找到 2 个 16 个地址的集群。

(来源:sites.google.com 上的 paperboyalgorithm)
接下来,如果我们通过设置 减少每个集群的最小地址数minA=12,我们会找到 12/12/8 个点的 3 个集群。

(来源:sites.google.com 上的 paperboyalgorithm)
为了证明该算法远非完美,这里是输出maxA=7,但我们得到了 6 个集群,其中一些集群很小。所以在确定参数的时候还是要猜测太多。请注意,r这里只有 5 个。

(来源:sites.google.com 上的 paperboyalgorithm)
只是出于好奇,我在一组更大的随机选择的点上尝试了该算法。我添加了下面的图片。
结论?这花了我半天的时间,效率低下,代码看起来很难看,而且速度比较慢。但它表明在短时间内产生一些结果是可能的。当然,这只是为了好玩;把它变成真正有用的东西是困难的部分。

(来源:sites.google.com 上的 paperboyalgorithm)

(来源:sites.google.com 上的 paperboyalgorithm)