为啥 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 相同?的主要内容,如果未能解决你的问题,请参考以下文章