k-means聚类算法的假设条件演示

k-means聚类算法是一种广泛使用的无监督学习方法,它试图将数据点划分为K个聚类,使得每个点与其所属聚类的中心点之间的距离最小。然而,k-means算法在某些情况下可能无法产生直观或理想的聚类结果。本文旨在通过生成不同类型的数据集来展示k-means在不同情况下的表现,包括非最优聚类数量、各向异性分布、不等方差和大小不一的聚类。

数据生成

使用make_blobs函数生成等轴高斯球体(isotropic gaussian blobs)。为了获得各向异性(anisotropic)高斯球体,需要定义一个线性变换。

import numpy as np from sklearn.datasets import make_blobs n_samples = 1500 random_state = 170 transformation = np.array([[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) # 各向异性球体

此外,还生成了具有不等方差的数据集和大小不一的聚类。

X_varied, y_varied = make_blobs(n_samples=n_samples, cluster_std=[1.0, 2.5, 0.5], random_state=random_state) # 不等方差 X_filtered = np.vstack((X[y==0][:500], X[y==1][:100], X[y==2][:10])) # 大小不一的聚类 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("高斯球体混合") axs[0, 1].scatter(X_aniso[:, 0], X_aniso[:, 1], c=y) axs[0, 1].set_title("各向异性分布球体") axs[1, 0].scatter(X_varied[:, 0], X_varied[:, 1], c=y_varied) axs[1, 0].set_title("不等方差") axs[1, 1].scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_filtered) axs[1, 1].set_title("大小不一的聚类") plt.suptitle("真实聚类") plt.show()

模型拟合与结果展示

接下来,使用生成的数据来展示k-means在不同情况下的行为。

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("非最优聚类数量") y_pred = KMeans(n_clusters=3, **common_params).fit_predict(X_aniso) axs[0, 1].scatter(X_aniso[:, 1], X_aniso[:, 0], c=y_pred) axs[0, 1].set_title("各向异性分布球体") 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("不等方差") 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("大小不一的聚类") plt.suptitle("k-means聚类结果") plt.show()

可能的解决方案

对于非最优聚类数量的问题,可以通过轮廓分析来选择正确的聚类数量。

y_pred = KMeans(n_clusters=3, **common_params).fit_predict(X) plt.scatter(X[:, 0], X[:, 1], c=y_pred) plt.title("最优聚类数量") plt.show()

对于大小不一的聚类,可以增加随机初始化的次数来避免找到次优的局部最小值。

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("大小不一的聚类\n多次初始化") plt.show()

对于各向异性和不等方差的问题,建议使用高斯混合模型(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("各向异性分布球体") y_pred = GaussianMixture(n_components=3).fit_predict(X_varied) ax2.scatter(X_varied[:, 0], X_varied[:, 1], c=y_pred) ax2.set_title("不等方差") plt.suptitle("高斯混合模型聚类") plt.show()

在高维空间中,欧几里得距离往往会膨胀。在执行k-means聚类之前,可以先运行降维算法来缓解这个问题,并加快计算速度。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485