50

今天我想学习一些关于K-means的东西。我已经了解算法并且我知道它是如何工作的。现在我正在寻找正确的 k...我发现肘部标准是一种检测正确 k 的方法,但我不明白如何将它与 scikit learn 一起使用?!在 scikit 学习中,我以这种方式对事物进行聚类

kmeans = KMeans(init='k-means++', n_clusters=n_clusters, n_init=10) 
kmeans.fit(data)

那么我应该为 n_clusters = 1...n 执行几次并观察错误率以获得正确的 k 吗?认为这将是愚蠢的,会花费很多时间?!

4

3 回答 3

80

如果事先不知道真正的标签(如您的情况),则K-Means clustering可以使用肘部标准或轮廓系数进行评估。

肘部标准方法:

肘部方法背后的想法是在给定的数据集上运行 k 均值聚类,以获得一系列 k 值(num_clusters例如 k=1 到 10),并且对于每个 k 值,计算误差平方和 (SSE)。

之后,为每个 k 值绘制 SSE 的折线图。如果折线图看起来像一条手臂 - 折线图下方的红色圆圈(如角度),则手臂上的“肘部”是最佳 k 的值(簇数)。在这里,我们希望最小化 SSE。随着k的增加,SSE趋向于向0减小(当k等于数据集中数据点的数量时,SSE为0,因为这样每个数据点都是自己的簇,它与中心之间没有误差它的集群)。

因此,目标是选择small value of k仍然具有低 SSE 的 a,并且肘部通常代表我们通过增加 k 开始收益递减的位置。

让我们考虑 iris 数据集,

import pandas as pd
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

iris = load_iris()
X = pd.DataFrame(iris.data, columns=iris['feature_names'])
#print(X)
data = X[['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)']]

sse = {}
for k in range(1, 10):
    kmeans = KMeans(n_clusters=k, max_iter=1000).fit(data)
    data["clusters"] = kmeans.labels_
    #print(data["clusters"])
    sse[k] = kmeans.inertia_ # Inertia: Sum of distances of samples to their closest cluster center
plt.figure()
plt.plot(list(sse.keys()), list(sse.values()))
plt.xlabel("Number of cluster")
plt.ylabel("SSE")
plt.show()

绘制上面的代码: 在此处输入图像描述

我们可以在图中看到,3 是 iris 数据集的最佳聚类数(红色圆圈),这确实是正确的。



轮廓系数法:

sklearn 文档中,

较高的轮廓系数分数与具有更好定义的集群的模型相关。轮廓系数是为每个样本定义的,由两个分数组成:`

a:样本与同一类中所有其他点之间的平均距离。

b:样本与下一个最近聚类中所有其他点之间的平均距离。

单个样本的轮廓系数为:

k现在,要找到for的最佳值KMeans,循环 1..n 中的 n_clustersKMeans并计算每个样本的轮廓系数。

较高的轮廓系数表明对象与其自己的簇匹配良好,而与相邻簇的匹配较差。

from sklearn.metrics import silhouette_score
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans

X = load_iris().data
y = load_iris().target
   
for n_cluster in range(2, 11):
    kmeans = KMeans(n_clusters=n_cluster).fit(X)
    label = kmeans.labels_
    sil_coeff = silhouette_score(X, label, metric='euclidean')
    print("For n_clusters={}, The Silhouette Coefficient is {}".format(n_cluster, sil_coeff))

输出 -

对于 n_clusters=2,轮廓系数是 0.680813620271
对于 n_clusters=3,轮廓系数是 0.552591944521
对于 n_clusters=4,轮廓系数是 0.496992849949
对于 n_clusters=5,轮廓系数是 0.488517550854对于 n_clusters=37550850 对于 n_clusters=37050850 轮廓系数是 33
501370 轮廓系数
对于 n_clusters=7,轮廓系数是 0.356303270516
对于 n_clusters=8,轮廓系数是 0.365164535737
对于 n_clusters=9,轮廓系数是 0.346583642095
对于 n_clusters=10,轮廓系数是 0.328266088778

正如我们所见,n_clusters=2具有最高的轮廓系数。这意味着 2 应该是集群的最佳数量,对吧?

但这就是问题所在。

Iris 数据集有 3 种花,这与 2 作为最佳聚类数相矛盾。因此,尽管n_clusters=2具有最高的轮廓系数,我们仍将n_clusters=3视为最佳集群数,因为 -

  1. 鸢尾花数据集有 3 个物种。(最重要的)
  2. n_clusters=2具有第二高的轮廓系数值。

所以选择n_clusters=3是最优的。虹膜数据集的集群。

选择最佳编号。集群的数量取决于数据集的类型和我们试图解决的问题。但在大多数情况下,采用最高的轮廓系数将产生最佳的聚类数。

希望能帮助到你!

于 2017-01-07T20:10:04.847 回答
36

肘部标准是一种视觉方法。我还没有看到一个强大的数学定义。但是 k-means 也是一种非常粗糙的启发式算法。

所以是的,您需要运行 k-means k=1...kmax,然后绘制生成的 SSQ 并决定“最佳”k。

存在 k-means 的高级版本,例如 X-means,它将开始k=2然后增加它,直到次要标准 (AIC/BIC) 不再改进。对 k-means 进行二等分是一种方法,它也从 k=2 开始,然后重复拆分集群,直到 k=kmax。您可能可以从中提取临时 SSQ。

无论哪种方式,我的印象是,在任何k-mean 非常好的实际用例中,您确实事先知道您需要的 k。在这些情况下,k-means 实际上与其说是一种“聚类”算法,不如说是一种向量量化算法。例如,将图像的颜色数量减少到 k。(通常您会选择 k 为例如 32,因为那是 5 位颜色深度并且可以以位压缩方式存储)。或者例如在视觉词袋方法中,您可以手动选择词汇量。一个流行的值似乎是 k=1000。然后,您并不太关心“集群”的质量,但重点是能够将图像减少到 1000 维稀疏向量。900 维或 1100 维表示的性能不会有本质上的不同。

对于实际的聚类任务,即当您想要手动分析生成的聚类时,人们通常使用比 k-means 更高级的方法。K-means 更像是一种数据简化技术。

于 2013-10-05T12:41:25.693 回答
4

这个答案的灵感来自 OmPrakash 所写的内容。这包含绘制 SSE 和剪影分数的代码。我给出的是一个通用代码片段,您可以在所有没有标签并想知道最佳集群数量的无监督学习情况下遵循该代码片段。有2个标准。1) 平方误差之和 (SSE) 和轮廓分数。您可以按照 OmPrakash 的回答进行解释。他在这方面做得很好。

假设您的数据集是数据框 df1。在这里,我使用了一个不同的数据集来展示我们如何使用这两个标准来帮助确定最佳集群数量。在这里,我认为 6 是正确的集群数。然后

range_n_clusters = [2, 3, 4, 5, 6,7,8]
elbow = []
ss = []
for n_clusters in range_n_clusters:
   #iterating through cluster sizes
   clusterer = KMeans(n_clusters = n_clusters, random_state=42)
   cluster_labels = clusterer.fit_predict(df1)
   #Finding the average silhouette score
   silhouette_avg = silhouette_score(df1, cluster_labels)
   ss.append(silhouette_avg)
   print("For n_clusters =", n_clusters,"The average silhouette_score is :", silhouette_avg)`
   #Finding the average SSE"
   elbow.append(clusterer.inertia_) # Inertia: Sum of distances of samples to their closest cluster center
fig = plt.figure(figsize=(14,7))
fig.add_subplot(121)
plt.plot(range_n_clusters, elbow,'b-',label='Sum of squared error')
plt.xlabel("Number of cluster")
plt.ylabel("SSE")
plt.legend()
fig.add_subplot(122)
plt.plot(range_n_clusters, ss,'b-',label='Silhouette Score')
plt.xlabel("Number of cluster")
plt.ylabel("Silhouette Score")
plt.legend()
plt.show()

用于比较两个标准的图表,以帮助我们找到最佳聚类值

于 2020-01-29T08:04:40.000 回答