Kmeans的优化版本,首先我们知道在kmeans正式聚类之前首先需要完成的就是初始化n个质心。同时,也正是因为这个原因,使得聚类算法存在着一个巨大的缺陷——收敛情况严重依赖于簇中心的初始化状况。试想一下,如果在初始化过程中很不巧的将个(或大多数)簇中心都初始化了到同一个簇中,那么在这种情况下聚类算法很大程度上都不会收敛到全局最小值。也就是说,当簇中心初始化的位置不得当时,聚类结果将会出现严重的错误。例子如下:
    K-means - 图1

    Kmeans++算法仅仅只是在初始化簇中心的方式上做了改进,其它地方同聚类算法一样。在初始化簇中心时的方法总结成一句话就是:逐个选取个簇中心,且离其它簇中心越远的样本点越有可能被选为下一个簇中心。 其具体做法如下:

    ①从数据集中随机(均匀分布)选取一个样本点作为第一个初始聚类中心;
    ②接着计算每个样本与当前已有聚类中心之间的最短距离,用表示;然后计算每个样本点被选为下一个聚类中心的概率,最后选择最大概率值所对应的样本点作为下一个簇中心;

    即把每个样本点到第一个初始质心的距离算出来平方相加,然后用每个样本到该质心的距离数值除以这个平方和,离该质心越远,则数值越大,除后得出的概率也就越大。

    ③重复第②步,直到选择出个聚类中心;(也就是说Kmeans++仍然需要需要指定簇的个数,也证明了Kmeans++仅在初始化簇的步骤上和Kmeans不同)

    需要注意的是sklearn中并没有Kmeans++这个包,而是被整合在了Kmeans的参数中:

    init: 即初始值选择的方式,可以为完全随机选择’random’,优化过的’k-means++‘或者自己指定初始化的k个质心。一般建议使用默认的’k-means++’。






    以下为可忽略的补充内容:** (没看过)
    手撕Kmeans++

    1. def InitialCentroid(x, K):
    2. c0_idx = int(np.random.uniform(0, len(x)))
    3. centroid = x[c0_idx].reshape(1, -1) # 选择第一个簇中心
    4. k = 1
    5. n = x.shape[0]
    6. while k < K:
    7. d2 = []
    8. for i in range(n):
    9. subs = centroid - x[i, :]
    10. dimension2 = np.power(subs, 2)
    11. dimension_s = np.sum(dimension2, axis=1) # sum of each row
    12. d2.append(np.min(dimension_s))
    13. new_c_idx = np.argmax(d2)
    14. centroid = np.vstack([centroid, x[new_c_idx]])
    15. k += 1
    16. return centroid
    17. if __name__ == '__main__':
    18. x, y = make_data()
    19. K = len(np.unique(y))
    20. # y_pred = kmeans(x, y)
    21. y_pred = kmeanspp_visual(x,y,K)
    22. nmi = normalized_mutual_info_score(y, y_pred)
    23. print("NMI by ours: ", nmi)
    24. model = KMeans(n_clusters=K, init='k-means++')
    25. model.fit(x)
    26. y_pred = model.predict(x)
    27. nmi = normalized_mutual_info_score(y, y_pred)
    28. print("NMI by sklearn: ", nmi)
    29. #结果:
    30. NMI by ours: 0.9456935014894648
    31. NMI by sklearn: 0.9456935014894648