Python scikit-learn 每次运行后聚类结果的变化

问题描述 投票:0回答:5

我有一堆句子,我想使用 scikit-learn 谱聚类对它们进行聚类。我已经运行了代码并得到了结果,没有问题。但是,每次我运行它都会得到不同的结果。我知道这是启动的问题,但我不知道如何解决。这是我在句子上运行的代码的一部分:

vectorizer = TfidfVectorizer(norm='l2',sublinear_tf=True,tokenizer=tokenize,stop_words='english',charset_error="ignore",ngram_range=(1, 5),min_df=1)
X = vectorizer.fit_transform(data)
# connectivity matrix for structured Ward
connectivity = kneighbors_graph(X, n_neighbors=5)
# make connectivity symmetric
connectivity = 0.5 * (connectivity + connectivity.T)
distances = euclidean_distances(X)
spectral = cluster.SpectralClustering(n_clusters=number_of_k,eigen_solver='arpack',affinity="nearest_neighbors",assign_labels="discretize")
spectral.fit(X)

数据是句子列表。每次运行代码时,我的聚类结果都会不同。如何使用谱聚类获得一致的结果。我的Kmean也有同样的问题。这是我的 Kmean 代码:

vectorizer = TfidfVectorizer(sublinear_tf=True,stop_words='english',charset_error="ignore")
X_data = vectorizer.fit_transform(data)
km = KMeans(n_clusters=number_of_k, init='k-means++', max_iter=100, n_init=1,verbose=0)
km.fit(X_data)

我感谢你的帮助。

python scikit-learn cluster-analysis k-means spectral
5个回答
35
投票

使用 k-means 时,您需要在

random_state
中设置
KMeans
参数(请参阅 文档)。将其设置为 int 或
RandomState
实例。

km = KMeans(n_clusters=number_of_k, init='k-means++', 
            max_iter=100, n_init=1, verbose=0, random_state=3425)
km.fit(X_data)

这很重要,因为 k 均值不是确定性算法。它通常以一些随机初始化过程开始,这种随机性意味着不同的运行将在不同的点开始。为伪随机数生成器播种可确保相同种子的随机性始终相同。

不过我不确定谱聚类的例子。来自 random_state 参数的

documentation
:“用于在
eigen_solver == 'amg'
和 K 均值初始化时初始化 lobpcg 特征向量分解的伪随机数生成器。” OP 的代码似乎不包含在这些情况下,尽管设置参数可能值得一试。


6
投票

正如其他人已经指出的那样,k-means 通常通过 randomized 初始化来实现。正是有心,你才能得到不同的结果。

该算法只是一种启发式方法。它可能会产生次优的结果。多次运行它可以让您更有机会找到好的结果。

在我看来,当每次运行的结果差异很大时,这表明数据根本无法与 k 均值很好地聚类。在这种情况下,你的结果并不比随机结果好多少。 如果数据确实适合k-means聚类,结果会相当稳定!如果它们不同,聚类可能不具有相同的大小,或者可能没有很好地分离;和其他算法可能会产生更好的结果。


1
投票

我有一个类似的问题,但我希望来自另一个分布的数据集以与原始数据集相同的方式进行聚类。例如,原始数据集的所有彩色图像都在

cluster 0
中,原始数据集的所有灰度图像都在
cluster 1
中。对于另一个数据集,我希望彩色图像/灰度图像也位于
cluster 0
cluster 1
中。

这是我从 Kaggler 窃取的代码 - 除了将

random_state
设置为种子之外,您还可以使用
KMeans
返回的 k 均值模型来对其他数据集进行聚类。这相当有效。但是,我找不到官方
scikit-Learn
文档这么说。

# reference - https://www.kaggle.com/kmader/normalizing-brightfield-stained-and-fluorescence
from sklearn.cluster import KMeans

seed = 42
def create_color_clusters(img_df,  cluster_count = 2, cluster_maker=None):
    if cluster_maker is None:
        cluster_maker = KMeans(cluster_count, random_state=seed)
        cluster_maker.fit(img_df[['Green', 'Red-Green', 'Red-Green-Sd']])

    img_df['cluster-id'] = np.argmin(cluster_maker.transform(img_df[['Green', 'Red-Green', 'Red-Green-Sd']]),-1)


    return img_df, cluster_maker

# Now K-Mean your images `img_df` to two clusters
img_df, cluster_maker = create_color_clusters(img_df, 2)
# Cluster another set of images using the same kmean-model
another_img_df, _ = create_color_clusters(another_img_df, 2, cluster_maker)

但是,即使将

random_state
设置为
int seed
也无法确保相同的数据在机器上始终以相同的顺序分组。相同的数据可能在一台机器上聚类为
group 0
,在另一台机器上聚类为
group 1
。但至少使用相同的 K-Means 模型(在我的代码中
cluster_maker
),我们确保来自另一个分布的数据将以与原始数据集相同的方式进行聚类。


0
投票

通常,当运行具有许多局部最小值的算法时,通常采用随机方法并以不同的初始状态多次运行算法。这将为您提供多个结果,并且通常会选择误差最低的结果作为最佳结果。

当我使用 K-Means 时,我总是运行几次并使用最佳结果。


0
投票

经过长时间的搜索和阅读,以下是我的意见。

  1. n_init=
    中使用 >5 或 10 的数字可在这些启动中产生最佳结果。
  2. random_state=
    中不同的数字会导致不同的聚类结果,根据我的经验,即使数据分布良好且良好,结果也可能会有一点偏差。
  3. 多次尝试大的 n_init 数字和 random_state 数字可以产生一致且良好的结果。计算机在处理时似乎优先考虑n_init
  4. 高维数据可能需要在 Kmeans 之前进行主成分分析 (PCA) link

总结答案:每次聚类结果的变化都是自然的,不用担心。您只需保存每次的结果即可。

© www.soinside.com 2019 - 2024. All rights reserved.