到目前为止,我们已经讨论了经典的k-means算法,它使用随机点作为初始中心点,若初始中心点选择不当,有可能会导致簇效果不佳或产生收敛速度慢等问题。解决此问题的一种方案就是在数据集上多次运行k-means算法,并根据误差平方和(SSE)选择性能最好的模型。另一种方案就是使用k-means++算法让初始中心点彼此尽可能远离,相比传统k-means算法,它能够产生更好、更一致的结果。[1]
k-means++算法的初始化过程可以概括如下:
1)初始化一个空的集合M,用于存储选定的k个中心点。
2)从输入样本中随机选定第一个中心点μ(j),并将其加入到集合M中。
3)对于集合M之外的任一样本点x(i),通过计算找到与其平方距离最小的样本d(x(i),M)2。
4)使用加权概率分布来随机选择下一个中心点μ(p)。
5)重复步骤2、3,直到选定k个中心点。
6)基于选定的中心点执行k-means算法。
通过scikit-learn的KMeans对象来实现k-means++算法,只需将init参数的值random替换为k-means++(默认值)即可。
k-means算法还有另一个问题,就是一个或多个簇的结果可能为空。但k-medoids或者模糊C-means算法中不存在这种问题,我们将在下一小节讨论这两种算法。不过,此问题在当前scikit-learn实现的k-means算法中是存在的。如果某个簇为空,算法将搜索距离空簇中心点最远的样本,然后将此最远样本点作为中心点。
当我们使用欧几里得距离作为度量标准将k-means算法应用到真实数据中时,需要保证所有特征值的范围处于相同尺度,必要时可使用z-score标准化或最小-最大缩放方法对数据进行预处理。
我们已经将簇结果存储在y_km中,并且讨论了k-means算法面临的挑战,现在对k-means算法的簇结果及其相应的簇中心做可视化展示。簇中心保存在KMeans对象的centers_属性中:
在下面的散点图中,我们可以看到,通过k-means算法得到的3个中心点位于各球状簇的圆心位置,在此数据集上,分组结果看起来是合理的。
虽然k-means算法在这一简单数据集上运行良好,但我们还要注意k-means算法面临的一些挑战。k-means的缺点之一就是我们必须指定一个先验的簇数量k,但在实际应用中,簇数量并非总是显而易见的,特别当我们面对的是一个无法可视化展现的高维数据集。k-means的另一个特点就是簇不可重叠,也不可分层,并且假定每个簇至少会有一个样本。
[1] D. Arthur and S. Vassilvitskii. k-means++: The Advantages of Careful Seeding. In Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms, pages 1027-1035. Society for Industrial and Applied Mathematics, 2007.