一、概述
把相似的数据汇总为簇的方法叫作聚类。k-means 算法是一种聚类算法,该算法非常简单,所以被广泛应用于数据分析。
我们来看一下k-means算法是如何进行聚类的。例如,将k-means算法应用于人工数据集,并把各个数据点分为3个簇,如图a所示。图b中的×表示的点是各个簇的重心,是k-means算法中簇的代表点。通过计算数据点与各重心的距离,找出离得最近的簇的重心,可以确定数据点所属的簇。
求簇的重心是k-means算法中最重要的计算。
二、算法说明
k-means 算法的典型计算步骤如下:
1. 从数据点中随机选择数量与簇的数量相同的数据点,作为这些簇的重心。
2. 计算数据点与各重心之间的距离,并将最近的重心所在的簇作为该数据点所属的簇。
3. 计算每个簇的数据点的平均值,并将其作为新的重心。
4. 重复步骤2和步骤3,继续计算,直到所有数据点不改变所属的簇,或者达到最大计算步数。
步骤1中的簇的数量是一个超参数,需要在训练时设置。对于有些数据集,我们可能很难决定要设置的簇的数量,在这种情况下,可以使用“详细说明”部分介绍的Elbow方法(肘方法)等技巧。
另外,有时选择的重心不好可能会导致步骤2和步骤3的训练无法顺利进行。比如在随机选择的重心之间太近等的情况下,就会出现这种问题。利用k-means++等方法,选择位置尽可能远离的数据点作为重心的初始值,就可以解决这个问题。
三、示例代码
下面是对鸢尾花数据集应用k-means算法的代码,簇的数量设置为3。
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
data = load_iris()
n_clusters = 3 # 将簇的数量设置为3
model = KMeans(n_clusters=n_clusters)
model.fit(data.data)
print(model.labels_) # 各数据点所属的簇
print(model.cluster_centers_) # 通过fit()计算得到的重心
四、详细说明
1. 聚类结果的评估方法
“算法说明”部分介绍了重心的更新方法。下面介绍k-means算法的评估方法,即如何判断聚类结果是好是坏。如图所示为对同一个数据集多次应用k-means算法的结果。
图a给人的印象是数据集划分得比较好,每个簇的区域清楚地分开了。不过从图形给人的印象来判断分析结果是一种定性的判断。另外,对于高维空间的数据,有可能难以进行可视化判断。因此,我们需要某种用于评估聚类结果是好是坏的定量的标准。
聚类结果的好坏可以通过计算簇内平方和(Within-Cluster Sum of Squares,WCSS)来定量评估(这个WCSS随着簇的数量的增加而变小,所以可以用于相同数量的簇的情况下的比较)。WCSS指的是对所有簇计算其所属的数据点与簇的重心之间距离的平方和,并将它们相加得到的值。这个值越小,说明聚类结果越好。
簇的重心与簇所属的数据点之间的距离越小,即数据点越在靠近簇的重心的地方集聚,WCSS越小。图a 的WCSS为50.1,图b的WCSS为124.5,因此可以得出左图的聚类结果更好的结论。
2. 使用Elbow方法确定簇的数量
在使用k-means算法时,首先要确定的就是簇的数量这个超参数,但有时我们并不知道应该将簇的值设置为多少合适。确定合理的簇的数量的一个方法是Elbow方法。
我们已经知道,随着簇的数量增加,WCSS会变小,但有时WCSS的变小幅度会从簇的数量为某个值时开始放缓。如图所示,在簇的数量增加到3的过程中,WCSS明显变小,但当簇的数量逐渐增加为4、 5……时,可以看到WCSS变小的幅度变缓了。Elbow方法将图形中看起来像手臂弯曲时的肘部的点作为簇的数量。在这个例子中,我们将簇的数量设置为3似乎很合适。
当没有很明确的理由来确定簇的数量或对数据知之甚少时,Elbow方法很有用。不过在实际的分析中,常常不会出现图中那样明显的“肘部”,所以Elbow方法的结果只不过是一种参考而已。