【问题标题】:Scikit Learn - K-Means - Elbow - criterionScikit Learn - K-Means - 弯头 - 标准
【发布时间】:2013-10-12 10:12:34
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    肘部标准法:

    肘部方法背后的想法是在给定数据集上运行 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()
    

    以上代码的情节:

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



    剪影系数法:

    来自sklearn documentation

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

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

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

    然后给出单个样本的轮廓系数为:

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

    更高的轮廓系数表明对象与其自己的聚类匹配良好,而与相邻聚类匹配不佳。

    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=6,轮廓系数为 0.370380309351
    对于 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 是最佳选择。虹膜数据集的聚类。

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

    希望对你有帮助!

    【讨论】:

    • 但是在你的例子中,n=2不是更高的轮廓系数吗?
    • 感谢@mattdeak 指出。在这种情况下,选择 n=3 将是最好的,因为 iris 数据集包含三个物种,但同时具有轮廓系数。不是最高的。这看起来与更高的轮廓系数相矛盾。导致最佳的集群数量。你可以试试gap static method
    • 请优化n_cluster==3。谢谢
    • 我正在尝试计算 silhouette score 并收到此错误:ValueError: Number of labels is 1. Valid values are 2 to n_samples - 1 (inclusive) 任何想法,这可能是什么原因?我还为此https://stackoverflow.com/questions/51382250/getting-error-number-of-labels-is-1-valid-values-are-2-to-n-samples-1-whil 提出了一个问题
    • 事实上,在我的数据集中,最好的剪影在 3 中,但实际上有两个类别。
    【解决方案2】:

    这个答案的灵感来自于 OmPrakash 所写的内容。这包含绘制 SSE 和剪影分数的代码。我给出的是一个通用代码 sn-p,您可以在所有没有标签并想知道最佳集群数量的无监督学习情况下遵循该代码。有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()
    

    【讨论】:

      【解决方案3】:

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

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

      存在高级版本的 k-means,例如 X-means,它将以 k=2 开头,然后增加它直到次要标准 (AIC/BIC) 不再改进。对 k-means 进行二等分是一种方法,它也从 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 更像是一种数据简化技术。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-29
        • 2012-06-29
        • 2020-02-29
        • 2021-01-19
        • 2019-01-14
        • 2017-09-19
        • 2019-01-21
        • 2020-01-11
        相关资源
        最近更新 更多