为啥 KMeans 集群标签并不总是与 set random_state 相同?

Posted

技术标签:

【中文标题】为啥 KMeans 集群标签并不总是与 set random_state 相同?【英文标题】:Why are KMeans cluster labels not always the same with set random_state?为什么 KMeans 集群标签并不总是与 set random_state 相同? 【发布时间】:2021-08-20 01:36:56 【问题描述】:

我有一个笔记本,我想在其中分析来自sklearn.cluster.KMeans 的集群。当我运行代码时,集群是相同的,但应用的标签可能会有所不同。这使我无法在笔记本的降价部分中按标签引用集群。我想知道为什么即使设置random_state 也会发生这种情况。看来random_state 只允许聚类相同,但为什么它每次也不应用相同的标签值?下面的代码将复制该问题,并且该图显示了标签如何变化。

from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(2)

x = np.random.normal(size=(1800, 2))
x[:700, 0] += 3
x[:700, 1] += 3
x[700:1200, 0] -= 0.5
x[700:1200, 1] -= 0.5
x[1200:, 0] += 3
x[1200:, 1] -= 3

np.random.shuffle(x)

first = None
while True: # it typically only takes a few iterations for a difference to occur
    km = KMeans(n_clusters=3, random_state=10)
    km.fit(x)
    pred = km.predict(x)
    if first is None:
        first = pred
    elif not np.array_equal(first, pred):
        print(first)
        print(pred)
        fig, ax = plt.subplots(1,2)
        for label in range(3):
            clusters = x[first == label]
            cluster = x[pred == label]
            ax[0].scatter(clusters[:, 0], clusters[:, 1], label=label)
            ax[1].scatter(cluster[:, 0], cluster[:, 1], label=label)
        break

ax[0].legend()
ax[1].legend()
plt.show()
[0 1 1 ... 2 0 0] # labels for first run
[0 2 2 ... 1 0 0] # different labels for later run

此外,我很困惑为什么使用相同的random_state 时详细输出不完全相同。

我注意到了几件事。首先是np.random.seed(1) 不会产生这个问题。因此,它似乎依赖于数据。其次,如果n_jobs=1 这似乎没有发生,但默认的n_jobs=None 会给出不同的结果(标签和详细输出)。并行化是否会导致这种情况发生?

很高兴知道这是我应该向 scikit-learn 开发人员报告的错误,还是我需要解决的特定问题。

【问题讨论】:

这个article 表示这种行为是故意的,但如果您需要修复它,有解决方法。 @MatthewBarlowe 是的,但是那篇文章没有设置 random_state 所以解释是因为集群中心是随机分布的。据我了解,在设置 random_state 时,应将集群中心初始化为相同的值。 这里是source code,它可能会帮助您回答为什么的问题。 @Kraigolas 我已经通读了源代码。随机性的唯一用途是集群中心初始化,所以我不明白变化的结果。后端是使用 Cython 编写的,C 代码是否可能引入了一些替代的随机状态? 【参考方案1】:

这似乎是由于舍入错误造成的。最好的标签会在当前惯性优于之前的最佳标签时更新。但是,由于舍入误差,惯性值可能等于当前值,但看起来稍好一些,并且不必要地更新了标签。目前有一个PR 正在解决这个问题。

【讨论】:

以上是关于为啥 KMeans 集群标签并不总是与 set random_state 相同?的主要内容,如果未能解决你的问题,请参考以下文章

如何在kmeans scikit learn中识别集群标签

如何使用 python 使用 K-Means 匹配具有真实标签的标签集群

K-means 与KNN 聚类算法

Scikit 聚类总是给出一个点聚类

使用不同颜色和标签的集群

如何从 KMeans 集群中获取集群的名称?