Scikit Learn - K-Means - Elbow - 标准

时间:2013-10-05 12:19:25

标签: python machine-learning scikit-learn cluster-analysis k-means

今天我正在努力学习一些关于K-means的知识。我已经理解了算法,我知道它是如何工作的。现在我正在寻找正确的k ...我发现肘部标准作为检测正确k的方法,但我不明白如何使用它与scikit学习?!在scikit中学习我以这种方式聚集事物

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

那么我应该多次为n_clusters = 1 ... n这样做并观察错误率以获得正确的k?认为这会很愚蠢并且需要花费很多时间?!

3 个答案:

答案 0 :(得分:48)

如果事先不知道真实标签(如您的情况),则可以使用Elbow Criterion或Silhouette Coefficient评估K-Means clustering

肘部标准方法:

elbow方法背后的想法是在给定数据集上运行k-means聚类,得到k(num_clusters的值范围,例如k = 1到10),并且对于k的每个值,计算总和平方误差(SSE)。

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

所以我们的目标是选择一个仍然具有较低SSE的small value of k,并且肘部通常代表我们通过增加k来开始减少收益的地方。

让我们考虑一下虹膜数据集,

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()

上述代码的图表: enter image description here

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



剪影系数法:

来自sklearn documentation

较高的Silhouette Coefficient得分与具有更好定义的聚类的模型相关。 Silhouette Coefficient是为每个样本定义的,由两个分数组成: `

  

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

     

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

单个样本的剪影系数则表示为:

s=b-a/max(a,b)

现在,要为k找到KMeans的最佳值,请在KMeans中为n_clusters循环1..n并计算每个样本的Silhouette系数。

较高的Silhouette Coefficient表示该对象与其自己的群集匹配良好且与相邻群集匹配不佳。

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,Silhouette系数为0.680813620271
对于n_clusters = 3,剪影系数为0.552591944521
对于n_clusters = 4,Silhouette系数为0.496992849949
对于n_clusters = 5,Silhouette系数为0.488517550854
对于n_clusters = 6,Silhouette系数为0.370380309351
对于n_clusters = 7,Silhouette系数为0.356303270516
对于n_clusters = 8,Silhouette系数为0.365164535737
对于n_clusters = 9,Silhouette系数为0.346583642095
对于n_clusters = 10,Silhouette系数为0.328266088778

正如我们所看到的, n_clusters = 2 具有最高的Silhouette系数。这意味着2应该是群集的最佳数量,对吗?

但这就是问题所在。

虹膜数据集有3种花,与2作为群的最佳数量相矛盾。因此,尽管 n_clusters = 2 具有最高的Silhouette系数,我们会将 n_clusters = 3 视为最佳簇数,因为 -

  1. 虹膜数据集有3种。 (最重要)
  2. n_clusters = 2 具有第二高的Silhouette Coefficient值。
  3. 因此选择 n_clusters = 3 是最佳选择。虹膜数据集的聚类。

    选择最佳编号。群集的大小取决于数据集的类型和我们试图解决的问题。但是大多数情况下,获得最高的Silhouette系数会产生最佳的聚类数。

    希望它有所帮助!

答案 1 :(得分:20)

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

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

存在k-means的高级版本,例如X-means,将以k=2开头,然后增加它,直到次要标准(AIC / BIC)不再提高。平分k均值是一种也以k = 2开始然后重复分裂簇直到k = kmax的方法。您可以从中提取临时SSQ。

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

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

答案 2 :(得分:3)

此答案受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()

Graphs used to compare both the criterion in order to help us find optimal cluster values