在数据分析中,聚类是一种常用的无监督学习方法,用于将数据点分组,使得同一组内的数据点相似度高,不同组之间的相似度低。KMeans算法是聚类分析中一个非常流行的算法,它通过迭代优化的方式将数据点分配到不同的簇中。然而,KMeans算法在处理某些特定类型的数据分布时可能会遇到挑战,例如非等方差或非等大小的聚类。本文将探讨这些问题,并提供可能的解决方案。
为了模拟不同的数据分布,可以使用Python中的make_blobs
函数生成高斯分布的数据点。通过定义线性变换,可以生成非等轴(椭圆形)的高斯分布。此外,还可以生成具有不同方差和不同大小的聚类。
from sklearn.datasets import make_blobs
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子和样本数量
random_state = 170
n_samples = 1500
# 生成等轴高斯分布
X, y = make_blobs(n_samples=n_samples, random_state=random_state)
# 定义线性变换生成非等轴高斯分布
transformation = np.array([[0.60834549, -0.63667341], [-0.40887718, 0.85253229]])
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
为了更好地理解数据的分布,可以使用散点图来可视化这些数据点。通过不同的颜色来区分不同的聚类,可以直观地看到数据点是如何被分组的。
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()
KMeans算法通过最小化样本到其分配簇的质心的欧几里得距离来进行聚类。然而,当数据分布是非等轴或具有不同方差时,KMeans算法可能无法得到理想的聚类结果。此外,如果聚类的大小不均匀,KMeans算法可能需要多次运行以避免陷入局部最小值。
from sklearn.cluster import KMeans
# 设置KMeans算法的参数
common_params = {"n_init": "auto", "random_state": random_state}
fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(12, 12))
# 应用KMeans算法到等轴高斯分布
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("非理想聚类数量")
# 应用KMeans算法到非等轴高斯分布
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("非等轴分布聚类")
# 应用KMeans算法到具有不同方差的高斯分布
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("不同方差聚类")
# 应用KMeans算法到不同大小的聚类
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("KMeans聚类结果")
plt.show()
为了解决KMeans算法在处理非等轴或具有不同方差数据分布时的局限性,可以考虑使用高斯混合模型(GaussianMixture)。与KMeans算法不同,高斯混合模型不要求簇具有相同的方差,因此更适合处理这类数据分布。此外,还可以通过增加随机初始化的次数来避免KMeans算法陷入局部最小值。
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()
在高维空间中,欧几里得距离往往会膨胀,导致KMeans算法的性能下降。在这种情况下,可以通过降维算法来缓解这个问题,并加速计算过程。如果已知聚类是等轴的、具有相似的方差且不太稀疏,KMeans算法是非常有效且快速的聚类算法之一。然而,如果需要多次运行算法以避免收敛到局部最小值,这种优势就会丧失。