每个聚类具有相同数量点的聚类过程?


25

我在有一些点,并且我想将这些点聚类,以便:X={x1,...,xn}Rp

  1. 每个簇包含相等数量的元素。(假设簇数除以。)Xn

  2. 每个聚类在某种意义上都是“空间内聚的”,就像来自均值的聚类一样。ķ

很容易想到很多满足其中一个或另一个要求的聚类过程,但是没有人知道同时获得两者的方法吗?


2
是否还指定了群集大小?然后,如上所述,这个问题对我来说似乎无法解决。考虑以下情况,其中:。如果您需要2个群集,则将得到不同的大小,或者没有“空间上的内聚性”。还是您想要“尽可能在空间上保持内聚”之类的方法-将最大内部集群距离最小化?另一种解决方案是允许将任何除数用作簇大小-但是,总会有个大小为簇的平凡解决方案。ñ=4p=1个X={-1个0.991个1.01}ññ1个
Erik P.

1
好点子。理想情况下,我希望在满足相等基数约束的同时“尽可能在空间上保持内聚”。但是我很想听听在这里也可以进行其他折衷的任何程序,因为也许可以对其进行调整。
不是Durrett'3

用分位数拆分数据就足够了吗?如果这些值相对于彼此不是单调的,那么我将看不到它们在空间上具有怎样的凝聚力。
celenius 2011年

4
最近有一些关于约束聚类的研究。Google google.com/search?q=constrained+k-means
Whuber

只是一个未经测试的想法。在聚类中,经常使用所谓的Silhouette统计。它显示了一个对象的聚簇程度,以及该对象可以加入的最佳其他邻居聚类。因此,您可以从K-MEANS或具有不同聚类n的其他分类开始。然后移动不太好归类对象(accorging的统计),以自己最好的相邻集群与较小ň,直到你获得平等ñ。我希望迭代:移动一些对象,重新计算统计信息,移动一些对象等。这将是一个折衷的过程。
ttnphns 2011年

Answers:


6

我建议采用两步法:

  1. 获得一个良好的聚类中心初始估计值,例如使用硬或模糊K均值。

  2. 使用全局最近邻居分配将点与聚类中心相关联:计算每个点与每个聚类中心之间的距离矩阵(您可以通过仅计算合理的距离来使问题小一些),复制每个聚类中心X次,并求解线性分配问题。对于每个聚类中心,您将获得与数据点完全匹配的X值,从而在总体上最小化了数据点与聚类中心之间的距离。

请注意,您可以在步骤2之后更新群集中心,然后重复步骤2,以基本上在每个群集中以固定点数运行K-means。不过,首先获得一个良好的初始猜测将是一个好主意。


4

尝试以下k均值变体:

初始化

  • k从数据集中随机选择中心,或者使用kmeans ++策略更好地选择中心
  • 对于每个点,计算到其最近的聚类中心的距离,并为此构建一个堆
  • 从堆中提取点,并将它们分配给最近的群集,除非该群集已满。如果是这样,请计算下一个最近的群集中心,然后重新插入堆中

最后,您应该进行分区,以满足每个群集+ -1个相同数量的对象的要求(确保最后几个群集也具有正确的数量。第一个m群集应该具有ceil对象,其余的完全是floor对象。)

迭代步骤

必要条件:每个群集的列表,其中包含“交换提案”(希望放在其他群集中的对象)。

E步骤:按照常规k均值计算更新的聚类中心

M步:遍历所有点(仅一批或全部一批)

计算距对象最近的群集中心/比当前群集更近的所有群集中心。如果是其他群集:

  • 如果另一个群集小于当前群集,只需将其移至新群集
  • 如果另一个集群(或任何距离较近的集群)有交换建议,则交换两个元素集群的分配(如果报价不只一个,则选择改进最大的一个)
  • 否则,请指出另一个集群的交换建议

聚类大小保持不变(+-天花板/地板差),对象仅从一个聚类移动到另一聚类,只要它能改善估计值即可。因此,它应该在某点收敛,例如k均值。不过,它可能会更慢(即更多迭代)。

我不知道它是否已经发布或实施过。这就是我会尝试的(如果我尝试k-means。会有更好的聚类算法。)

一个很好的起点可能是ELKI中的k-means实现,它似乎已经支持三种不同的初始化(包括k-means ++),并且作者说他们还希望拥有不同的迭代策略,以涵盖所有常见的模块化方式的变体(例如Lloyd,MacQueen等)。


2
ELKI作为教程和教程“扩展”模块中包含了类似的方法:elki.dbs.ifi.lmu.de/wiki/Tutorial/SameSizeKMeans
Erich Schubert

3

这是一个优化问题。我们有一个开放源代码的Java库来解决此问题(聚簇每个集群的数量必须在设置范围之间)。但是,您需要的总点数最多为几千个-不超过5000或10000。

图书馆在这里:

https://github.com/PGWelch/territorium/tree/master/territorium.core

该库本身是针对地理/ GIS类型问题而设置的-因此您将看到对X和Y,纬度和经度,客户,距离和时间等的引用。您可以忽略“地理”元素,而将其用作纯集群器。

您提供了一组初始为空的输入集群,每个集群具有最小和最大目标数量。聚类器将使用基于启发式的优化算法(交换,移动等)将点分配给您的输入聚类。在优化中,它首先优先考虑将每个群集保持在其最小和最大数量范围内,然后其次将群集中所有点与群集中心点之间的距离最小化,因此群集在空间上具有凝聚力。

您可以使用此接口为求解器提供点之间的度量函数(即距离函数):

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/main/java/com/opendoorlogistics/territorium/problem/TravelMatrix.java

该度量标准实际上是为了返回距离和“时间”而构造的,因为它是针对基于旅行的地理问题而设计的,但是对于任意聚类问题,只需将“时间”设置为零,而距离是您要在之间使用的实际度量标准点。

您将在此类中设置您的问题:

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/main/java/com/opendoorlogistics/territorium/problem/Problem.java

您的积分将是“客户”,其数量将是1。在客户类别中,假设您要在TravelMatrix返回的“距离”字段中返回度量距离,请确保您设置costPerUnitTime = 0和costPerUnitDistance = 1。

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/main/java/com/opendoorlogistics/territorium/problem/Customer.java

请参阅此处以了解运行求解器的示例:

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/test/java/com/opendoorlogistics/territorium/TestSolver.java



2

最近,我自己需要一个不太大的数据集。我的回答尽管运行时间相对较长,但可以保证收敛到局部最优值。

def eqsc(X, K=None, G=None):
    "equal-size clustering based on data exchanges between pairs of clusters"
    from scipy.spatial.distance import pdist, squareform
    from matplotlib import pyplot as plt
    from matplotlib import animation as ani    
    from matplotlib.patches import Polygon   
    from matplotlib.collections import PatchCollection
    def error(K, m, D):
        """return average distances between data in one cluster, averaged over all clusters"""
        E = 0
        for k in range(K):
            i = numpy.where(m == k)[0] # indeces of datapoints belonging to class k
            E += numpy.mean(D[numpy.meshgrid(i,i)])
        return E / K
    numpy.random.seed(0) # repeatability
    N, n = X.shape
    if G is None and K is not None:
        G = N // K # group size
    elif K is None and G is not None:
        K = N // G # number of clusters
    else:
        raise Exception('must specify either K or G')
    D = squareform(pdist(X)) # distance matrix
    m = numpy.random.permutation(N) % K # initial membership
    E = error(K, m, D)
    # visualization
    #FFMpegWriter = ani.writers['ffmpeg']
    #writer = FFMpegWriter(fps=15)
    #fig = plt.figure()
    #with writer.saving(fig, "ec.mp4", 100):
    t = 1
    while True:
        E_p = E
        for a in range(N): # systematically
            for b in range(a):
                m[a], m[b] = m[b], m[a] # exchange membership
                E_t = error(K, m, D)
                if E_t < E:
                    E = E_t
                    print("{}: {}<->{} E={}".format(t, a, b, E))
                    #plt.clf()
                    #for i in range(N):
                        #plt.text(X[i,0], X[i,1], m[i])
                    #writer.grab_frame()
                else:
                    m[a], m[b] = m[b], m[a] # put them back
        if E_p == E:
            break
        t += 1           
    fig, ax = plt.subplots()
    patches = []
    for k in range(K):
        i = numpy.where(m == k)[0] # indeces of datapoints belonging to class k
        x = X[i]        
        patches.append(Polygon(x[:,:2], True)) # how to draw this clock-wise?
        u = numpy.mean(x, 0)
        plt.text(u[0], u[1], k)
    p = PatchCollection(patches, alpha=0.5)        
    ax.add_collection(p)
    plt.show()

if __name__ == "__main__":
    N, n = 100, 2    
    X = numpy.random.rand(N, n)
    eqsc(X, G=3)

1
感谢您的贡献,@ user2341646。您介意添加一些说明来解释此解决方案是什么,如何工作以及为什么是解决方案吗?
gung-恢复莫妮卡

好。基本上,该算法从随机的成员资格分配开始,但是一个集群中有接近G个成员,总体上有K个集群。我们定义误差函数,该函数测量一个集群中数据之间的平均距离,该平均距离是所有集群中的平均值。系统地浏览所有数据对,我们看看交换这两个数据的成员资格是否会导致较低的错误。如果是这样,我们将更新最低可能的错误,否则我们将撤消成员资格开关。我们这样做直到一整遍没有剩下任何动作为止。
亚历山大·凯恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.