【问题标题】:How Could One Implement the K-Means++ Algorithm?如何实现 K-Means++ 算法?
【发布时间】:2011-07-24 21:24:15
【问题描述】:

我无法完全理解K-Means++ algorithm。我很感兴趣第一个k 质心是如何选择的,即初始化,其余部分就像原始K-Means algorithm 一样。

  1. 使用的概率函数是基于距离还是高斯?
  2. 同时选择最远的点(距其他质心)作为新质心。

我会欣赏一步一步的解释和一个例子。 Wikipedia 中的那个不够清楚。还有一个很好注释的源代码也会有所帮助。如果您使用 6 个数组,那么请告诉我们哪一个是做什么用的。

【问题讨论】:

标签: algorithm language-agnostic machine-learning cluster-analysis k-means


【解决方案1】:

有趣的问题。感谢您让我注意到这篇论文 - K-Means++: The Advantages of Careful Seeding

简单来说,聚类中心最初是从输入观察向量集中随机选择的,如果x 不在任何先前选择的中心附近,则选择向量x 的概率很高。

这是一个一维的例子。我们的观察结果是 [0, 1, 2, 3, 4]。令第一个中心c1 为0。下一个聚类中心c2 为x 的概率与||c1-x||^2 成正比。因此,P(c2 = 1) = 1a,P(c2 = 2) = 4a,P(c2 = 3) = 9a,P(c2 = 4) = 16a,其中 a = 1/(1+4+9+ 16).

假设 c2=4。那么,P(c3 = 1) = 1a,P(c3 = 2) = 4a,P(c3 = 3) = 1a,其中a = 1/(1+4+1)。

我已经用 Python 编写了初始化过程;不知道对你有没有帮助。

def initialize(X, K):
    C = [X[0]]
    for k in range(1, K):
        D2 = scipy.array([min([scipy.inner(c-x,c-x) for c in C]) for x in X])
        probs = D2/D2.sum()
        cumprobs = probs.cumsum()
        r = scipy.rand()
        for j,p in enumerate(cumprobs):
            if r < p:
                i = j
                break
        C.append(X[i])
    return C

编辑澄清:cumsum 的输出为我们提供了划分区间 [0,1] 的边界。这些分区的长度等于相应点被选为中心的概率。那么,由于r 是在[0,1] 之间统一选择的,它将恰好落入这些区间之一(因为break)。 for 循环检查r 在哪个分区。

例子:

probs = [0.1, 0.2, 0.3, 0.4]
cumprobs = [0.1, 0.3, 0.6, 1.0]
if r < cumprobs[0]:
    # this event has probability 0.1
    i = 0
elif r < cumprobs[1]:
    # this event has probability 0.2
    i = 1
elif r < cumprobs[2]:
    # this event has probability 0.3
    i = 2
elif r < cumprobs[3]:
    # this event has probability 0.4
    i = 3

【讨论】:

  • 因此,对于 X 中的每个点,我们都会生成一个概率。然后 cumsum 应该重视这些概率。我认为这个想法是对概率更高的点给予更多的权重,所以当我们进行“随机质心选择”时,我们会在其中选择。但是我们怎么知道我们应该把更多的权重放在哪些点上(?) - 我们还没有对 probs 数组进行排序,而 cumsum 函数使数组末尾的那些具有更大的权重(cumsum 定义)。
  • 我的意思是 cumsum 具有向右累积的特定行为(x1
  • 为了执行我使用'numpy'而不是'scipy'的代码。另外为了得到正确的划分,我使用了'from future import division',否则概率都是 [0,0,...]。
  • 如果您有大量积分会怎样?你能检查我的问题stats.stackexchange.com/questions/144190/… 吗?谢谢
  • 如果概率落入相同的值怎么办,我的意思是如果 c1 = [20,19,80] 并且顺便说一下 c2 也落入与 c1 相同的值。代码应该被修复吗?如果 X[i] 不在 C 中,则添加以下代码行
【解决方案2】:

一个班轮。

假设我们需要选择2个聚类中心,而不是全部随机选择{就像我们在简单的k均值中所做的},我们将随机选择第一个,然后找到离第一个中心最远的点{这些点很可能不属于第一个聚类中心,因为它们离它很远}并在这些远点附近分配第二个聚类中心。

【讨论】:

    【解决方案3】:

    我已经根据 Toby Segaran 的《集体智能》一书和此处提供的 k-menas++ 初始化准备了 k-means++ 的完整源代码实现。

    这里确实有两个距离函数。对于初始质心,使用基于 numpy.inner 的标准质心,然后使用 Pearson 固定质心。也许 Pearson 也可以用于初始质心。他们说这样更好。

    from __future__ import division
    
    def readfile(filename):
      lines=[line for line in file(filename)]
      rownames=[]
      data=[]
      for line in lines:
        p=line.strip().split(' ') #single space as separator
        #print p
        # First column in each row is the rowname
        rownames.append(p[0])
        # The data for this row is the remainder of the row
        data.append([float(x) for x in p[1:]])
        #print [float(x) for x in p[1:]]
      return rownames,data
    
    from math import sqrt
    
    def pearson(v1,v2):
      # Simple sums
      sum1=sum(v1)
      sum2=sum(v2)
    
      # Sums of the squares
      sum1Sq=sum([pow(v,2) for v in v1])
      sum2Sq=sum([pow(v,2) for v in v2])    
    
      # Sum of the products
      pSum=sum([v1[i]*v2[i] for i in range(len(v1))])
    
      # Calculate r (Pearson score)
      num=pSum-(sum1*sum2/len(v1))
      den=sqrt((sum1Sq-pow(sum1,2)/len(v1))*(sum2Sq-pow(sum2,2)/len(v1)))
      if den==0: return 0
    
      return 1.0-num/den
    
    import numpy
    from numpy.random import *
    
    def initialize(X, K):
        C = [X[0]]
        for _ in range(1, K):
            #D2 = numpy.array([min([numpy.inner(c-x,c-x) for c in C]) for x in X])
            D2 = numpy.array([min([numpy.inner(numpy.array(c)-numpy.array(x),numpy.array(c)-numpy.array(x)) for c in C]) for x in X])
            probs = D2/D2.sum()
            cumprobs = probs.cumsum()
            #print "cumprobs=",cumprobs
            r = rand()
            #print "r=",r
            i=-1
            for j,p in enumerate(cumprobs):
                if r 0:
            for rowid in bestmatches[i]:
              for m in range(len(rows[rowid])):
                avgs[m]+=rows[rowid][m]
            for j in range(len(avgs)):
              avgs[j]/=len(bestmatches[i])
            clusters[i]=avgs
    
      return bestmatches
    
    rows,data=readfile('/home/toncho/Desktop/data.txt')
    
    kclust = kcluster(data,k=4)
    
    print "Result:"
    for c in kclust:
        out = ""
        for r in c:
            out+=rows[r] +' '
        print "["+out[:-1]+"]"
    
    print 'done'
    

    数据.txt:

    p1 1 5 6
    p2 9 4 3
    p3 2 3 1
    p4 4 5 6
    p5 7 8 9
    p6 4 5 4
    p7 2 5 6
    p8 3 4 5
    p9 6 7 8
    

    【讨论】:

    • 代码在这里可用:a-algorithms 用于 CPython 和 IronPython。
    猜你喜欢
    • 2013-07-24
    • 2020-03-10
    • 2014-02-02
    • 2021-05-04
    • 2011-09-04
    • 2013-07-03
    • 2012-11-11
    • 2010-12-05
    • 2017-04-20
    相关资源
    最近更新 更多