我用 Java 编写了一个低效但简单的算法,看看我可以多接近在一组点上进行一些基本的聚类,或多或少如问题中所述。
ps
如果 (x,y) 坐标指定为int
s ,则该算法适用于列表。它还需要三个其他参数:
- radius (
r
): 给定一个点,扫描附近点的半径是多少
- 最大地址(
maxA
):每个集群的最大地址(点)数是多少?
- 最小地址 (
minA
):每个集群的最小地址
设置limitA=maxA
。
主迭代:
初始化空列表possibleSolutions
。
外部迭代:对于p
. ps
初始化空列表pclusters
。定义了一个点的工作清单wps=copy(ps)
。工作点wp=p
。
内部迭代: whilewps
不为空。删除 中的点wp
。wps
确定距离 < fromwpsInRadius
的所有点。根据与 的距离升序排列。将第一点保留在. 这些点形成一个新的集群(点列表)。添加到. 从中删除点。如果wps
r
wp
wpsInRadius
wp
min(limitA, sizeOf(wpsInRadius))
wpsInRadius
pcluster
pcluster
pclusters
pcluster
wps
wps
不为空,wp=wps[0]
继续内迭代。
结束内部迭代。
获得集群列表pclusters
。将此添加到possibleSolutions
.
结束外部迭代。
我们有一个集群列表中的p
每一个。然后每一个都被加权。如果是(全局)中每个簇的平均点数,并且是每个(全局)中的平均簇数,那么这是使用这两个变量来确定权重的函数:ps
pclusters
possibleSolutions
pclusters
avgPC
possibleSolutions
avgCSize
pclusters
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)