注意
转到结尾 下载完整的示例代码。或通过 JupyterLite 或 Binder 在您的浏览器中运行此示例
k 均值假设演示#
此示例旨在说明k均值算法产生非直观且可能不理想的聚类的情况。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
数据生成#
函数make_blobs
生成各向同性(球形)高斯混合数据。为了获得各向异性(椭圆形)高斯混合数据,必须定义一个线性变换
。
import numpy as np
from sklearn.datasets import make_blobs
n_samples = 1500
random_state = 170
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
X, y = make_blobs(n_samples=n_samples, random_state=random_state)
X_aniso = np.dot(X, transformation) # Anisotropic blobs
X_varied, y_varied = make_blobs(
n_samples=n_samples, cluster_std=[1.0, 2.5, 0.5], random_state=random_state
) # Unequal variance
X_filtered = np.vstack(
(X[y == 0][:500], X[y == 1][:100], X[y == 2][:10])
) # Unevenly sized blobs
y_filtered = [0] * 500 + [1] * 100 + [2] * 10
我们可以将生成的数据可视化。
import matplotlib.pyplot as plt
fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(12, 12))
axs[0, 0].scatter(X[:, 0], X[:, 1], c=y)
axs[0, 0].set_title("Mixture of Gaussian Blobs")
axs[0, 1].scatter(X_aniso[:, 0], X_aniso[:, 1], c=y)
axs[0, 1].set_title("Anisotropically Distributed Blobs")
axs[1, 0].scatter(X_varied[:, 0], X_varied[:, 1], c=y_varied)
axs[1, 0].set_title("Unequal Variance")
axs[1, 1].scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_filtered)
axs[1, 1].set_title("Unevenly Sized Blobs")
plt.suptitle("Ground truth clusters").set_y(0.95)
plt.show()
拟合模型并绘制结果#
现在使用先前生成的数据来展示KMeans
在以下场景中的表现:
非最优聚类数量:在实际设置中,没有唯一定义的真实聚类数量。必须根据基于数据的标准和预期目标的知识来确定合适的聚类数量。
各向异性分布的数据点:k均值算法最小化样本与其所属聚类质心的欧几里得距离。因此,k均值算法更适用于各向同性且正态分布的聚类(即球形高斯分布)。
方差不等:k均值算法等价于对k个具有相同方差但均值可能不同的高斯分布的“混合”进行最大似然估计。
大小不等的数据点:没有关于k均值算法的理论结果表明它需要相似的聚类大小才能表现良好,但是最小化欧几里得距离确实意味着,问题越稀疏和高维,就越需要使用不同的质心种子运行算法以确保全局最小惯性。
from sklearn.cluster import KMeans
common_params = {
"n_init": "auto",
"random_state": random_state,
}
fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(12, 12))
y_pred = KMeans(n_clusters=2, **common_params).fit_predict(X)
axs[0, 0].scatter(X[:, 0], X[:, 1], c=y_pred)
axs[0, 0].set_title("Non-optimal Number of Clusters")
y_pred = KMeans(n_clusters=3, **common_params).fit_predict(X_aniso)
axs[0, 1].scatter(X_aniso[:, 0], X_aniso[:, 1], c=y_pred)
axs[0, 1].set_title("Anisotropically Distributed Blobs")
y_pred = KMeans(n_clusters=3, **common_params).fit_predict(X_varied)
axs[1, 0].scatter(X_varied[:, 0], X_varied[:, 1], c=y_pred)
axs[1, 0].set_title("Unequal Variance")
y_pred = KMeans(n_clusters=3, **common_params).fit_predict(X_filtered)
axs[1, 1].scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_pred)
axs[1, 1].set_title("Unevenly Sized Blobs")
plt.suptitle("Unexpected KMeans clusters").set_y(0.95)
plt.show()
可能的解决方案#
关于如何找到正确的数据点数量的示例,请参见使用轮廓分析选择KMeans聚类中的聚类数量。在这种情况下,只需设置n_clusters=3
即可。
y_pred = KMeans(n_clusters=3, **common_params).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.title("Optimal Number of Clusters")
plt.show()
为了处理大小不等的数据点,可以增加随机初始化的次数。在本例中,我们将n_init
设置为10
,以避免找到次优局部最小值。有关更多详细信息,请参见使用k均值聚类稀疏数据。
y_pred = KMeans(n_clusters=3, n_init=10, random_state=random_state).fit_predict(
X_filtered
)
plt.scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_pred)
plt.title("Unevenly Sized Blobs \nwith several initializations")
plt.show()
由于各向异性和方差不等是k均值算法的实际限制,因此我们建议改用GaussianMixture
,它也假设高斯聚类,但不对方差施加任何约束。请注意,仍然需要找到正确的数据点数量(参见高斯混合模型选择)。
有关其他聚类方法如何处理各向异性或方差不等的数据点的示例,请参见示例比较玩具数据集上的不同聚类算法。
from sklearn.mixture import GaussianMixture
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12, 6))
y_pred = GaussianMixture(n_components=3).fit_predict(X_aniso)
ax1.scatter(X_aniso[:, 0], X_aniso[:, 1], c=y_pred)
ax1.set_title("Anisotropically Distributed Blobs")
y_pred = GaussianMixture(n_components=3).fit_predict(X_varied)
ax2.scatter(X_varied[:, 0], X_varied[:, 1], c=y_pred)
ax2.set_title("Unequal Variance")
plt.suptitle("Gaussian mixture clusters").set_y(0.95)
plt.show()
最终说明#
在高维空间中,欧几里得距离往往会膨胀(本示例中未显示)。在k均值聚类之前运行降维算法可以减轻这个问题并加快计算速度(参见示例使用k均值聚类文本文档)。
如果已知聚类是各向同性的,具有相似的方差并且不太稀疏,则k均值算法非常有效,并且是可用的最快聚类算法之一。如果必须多次重新启动该算法以避免收敛到局部最小值,则会失去这种优势。
脚本总运行时间:(0 分钟 1.145 秒)
相关示例