编辑:就像casperOne指出的那样,这个问题是重复的。无论如何,这是一个更普遍的问题,涵盖了这一个:https://stats.stackexchange.com/questions/8744/clustering-procedure-where-each-cluster-has-an-equal-number-of-points
我的要求
在一个项目中,我需要将n个点(x,y)分组为相同大小的k个簇(n / k)。其中x和y是双浮点数,n的范围是100到10000,k的范围是2到100.在算法运行之前,k也是已知的。
我的实验
我开始使用http://en.wikipedia.org/wiki/K-means_clustering算法来解决这个问题,该算法非常快速地生成大致相同大小的k个簇。
但我的问题是,K-means产生大小相同的簇,我需要簇的大小完全相同(或者更精确:我需要它们在地板之间有一个大小(n / k)和ceil(n / k))。
在你向我指出之前,是的,我在这里尝试了第一个答案K-means algorithm variation with equal cluster size,这听起来不错。
主要思想是通过K-means对集群产生的数组进行后处理。从最大的集群到最小的集群。我们通过将额外的点移动到其他最近的集群来减少具有超过n / k成员的集群的大小。单独留下已经减少的集群。
这是我实现的伪代码:
n is the number of point
k is the number of cluster
m = n / k (the ideal cluster size)
c is the array of cluster after K-means
c' = c sorted by size in descending order
for each cluster i in c' where i = 1 to k - 1
n = size of cluster i - m (the number of point to move)
loop n times
find a point p in cluster i with minimal distance to a cluster j in c' where j > i
move point p from cluster i to cluster j
end loop
recalculate centroids
end for each
这个算法的问题是在过程结束时(当我接近k时),我们必须在c'中选择一个簇j(其中j> i因为我们需要单独留下簇我们发现这个集群j可能远离集群i,从而打破了集群的概念。
我的问题
是否有可以满足我要求的K-means算法或K-means变体,或者我从一开始就错了,我需要找到其他的聚类算法?
PS:我不介意自己实现解决方案,但如果我可以使用库,理想情况下可以使用JAVA,那就太棒了。
答案 0 :(得分:5)
尝试这种k-means变体:
<强>初始化强>:
k
个中心,甚至更好地使用kmeans ++策略最后,你应该有一个分区,满足你对每个集群+ -1相同数量的对象的要求(确保最后几个集群也有正确的数字。第一个m
集群应该有ceil
个对象,其余为floor
个对象。)
请注意,使用堆确保群集保持凸起:如果它们不再是凸起的,那么就会有更好的交换候选者。
迭代步骤:
必需条件:每个群集的列表都包含“交换提议”(更喜欢位于不同群集中的对象)。
E 步骤:计算更新的群集中心,如常规k-means
M 步骤:迭代所有点(一个或一个中只有一个)
计算距离当前群集较近的对象/所有群集中心的最近群集中心。如果它是一个不同的集群:
群集大小保持不变(+ - 小区/楼层差异),对象仅从一个群集移动到另一个群集,只要它导致估计的改进。因此它应该像k-means一样收敛。但它可能会慢一些(即更多迭代)。
我不知道之前是否已经发布或实施过。这就是我想尝试的(如果我尝试k-means。有更好的聚类算法。)
答案 1 :(得分:2)
不是这个主题的专家,我曾经需要提出一个简单的算法来聚集地图上的位置,其中每个点都需要成为群集的一部分,并且群集以多种方式绑定(不仅仅是大小(即点数),但也取决于不同因素的其他一些措施。
首先找到“困难”点,然后从那里发展成群,我得到了最好的结果。 “困难”点将是难以达到的点,例如因为它们会独自躺在整个区域的郊区,或者因为它们比其他点更能帮助击中另一个群集边界条件。这有助于整齐地对齐簇,留下很少的孤独者和相应的手工来放置它们。
如果您当前的算法通常会在最后找到这些难点,这可能会有所帮助。