首页 > 解决方案 > 为什么 KMeans 集群标签并不总是与 set random_state 相同?

问题描述

我有一个笔记本,我想从中分析集群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

kmeans 绘图差异

此外,我很困惑为什么使用相同的random_state.

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

很高兴知道这是否是我应该向 scikit-learn 开发人员报告的错误,或者这是一个特定于我的案例的问题,需要解决。

标签: pythonscikit-learnk-means

解决方案


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


推荐阅读