← 返回首页
🤖

K-Means聚类算法详解

📂 ai ⏱ 2 min 245 words

K-Means聚类算法详解

K-Means是经典的无监督学习算法,通过将数据划分为K个簇来发现数据中的内在结构。

算法原理

K-Means的目标是最小化簇内平方和(WCSS),即每个点到其所属簇中心的距离之和。

算法步骤

  1. 随机选择K个初始聚类中心
  2. 将每个样本分配到最近的聚类中心
  3. 重新计算每个簇的中心点
  4. 重复步骤2-3直到收敛
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler

# 生成模拟数据
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# K-Means聚类
kmeans = KMeans(n_clusters=4, init='k-means++', n_init=10, random_state=42)
y_pred = kmeans.fit_predict(X_scaled)

print(f"聚类中心:\n{kmeans.cluster_centers_}")
print(f"惯性(WCSS): {kmeans.inertia_:.2f}")

肘部法则选择K值

肘部法则通过绘制不同K值对应的WCSS曲线,选择曲线"拐点"作为最优K值。

# 测试不同K值
inertias = []
K_range = range(1, 11)

for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    kmeans.fit(X_scaled)
    inertias.append(kmeans.inertia_)

# 绘制肘部法则图
plt.figure(figsize=(8, 5))
plt.plot(K_range, inertias, 'bo-', linewidth=2, markersize=8)
plt.xlabel('簇数量K')
plt.ylabel('惯性(WCSS)')
plt.title('肘部法则选择最优K值')
plt.grid(True, alpha=0.3)
plt.show()

# 输出各K值的惯性
for k, inertia in zip(K_range, inertias):
    print(f"K={k}: 惯性={inertia:.2f}")

轮廓系数评估

轮廓系数衡量样本与其所属簇的相似度,取值范围[-1, 1],越大越好。

from sklearn.metrics import silhouette_score

# 计算不同K值的轮廓系数
silhouette_scores = []
for k in range(2, 11):
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    labels = kmeans.fit_predict(X_scaled)
    score = silhouette_score(X_scaled, labels)
    silhouette_scores.append(score)
    print(f"K={k}: 轮廓系数={score:.4f}")

# 最优K值
best_k = list(range(2, 11))[np.argmax(silhouette_scores)]
print(f"\n最优K值: {best_k}")

可视化聚类结果

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 原始数据
axes[0].scatter(X_scaled[:, 0], X_scaled[:, 1], c=y_true, cmap='viridis', s=50)
axes[0].set_title('原始数据(真实标签)')

# K-Means结果
axes[1].scatter(X_scaled[:, 0], X_scaled[:, 1], c=y_pred, cmap='viridis', s=50)
axes[1].scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
                c='red', marker='X', s=200, label='聚类中心')
axes[1].set_title('K-Means聚类结果')
axes[1].legend()

plt.tight_layout()
plt.show()

K-Means++初始化

K-Means++通过优化初始中心选择,避免陷入局部最优。

# K-Means++ (默认)
kmeans_pp = KMeans(n_clusters=4, init='k-means++', n_init=10, random_state=42)
kmeans_pp.fit(X_scaled)

# 随机初始化
kmeans_random = KMeans(n_clusters=4, init='random', n_init=10, random_state=42)
kmeans_random.fit(X_scaled)

print(f"K-Means++ 惯性: {kmeans_pp.inertia_:.2f}")
print(f"随机初始化 惯性: {kmeans_random.inertia_:.2f}")

K-Means的局限性

K-Means假设簇是球形的,对非球形数据效果不佳。对噪声和异常值敏感,需要预先指定K值。

# 非球形数据示例
from sklearn.datasets import make_moons

X_moons, y_moons = make_moons(n_samples=300, noise=0.05, random_state=42)
kmeans_moons = KMeans(n_clusters=2, random_state=42)
y_moons_pred = kmeans_moons.fit_predict(X_moons)

silhouette = silhouette_score(X_moons, y_moons_pred)
print(f"非球形数据轮廓系数: {silhouette:.4f}")
print("K-Means对非球形簇效果较差,可考虑DBSCAN等算法")

总结

特性 说明
优点 简单高效、可扩展性强
缺点 需预设K值、假设球形簇
适用场景 客户细分、图像压缩、文档聚类

K-Means是聚类分析的入门算法,理解其原理为后续学习更复杂的聚类方法奠定基础。