人工智能之核心基础 机器学习 第九章 聚类算法

0 阅读7分钟

人工智能之核心基础 机器学习

第九章 聚类算法


9.1 K-Means 聚类

🎯 核心思想:让“群内紧凑,群间分离”

想象你要在操场上把学生分成 K 组做游戏,目标是:

  • 每组学生站得尽量近
  • 不同组之间离得尽量远

K-Means 就是通过不断调整“组长位置”(聚类中心)来实现这个目标。


🔑 算法步骤(迭代优化)

  1. 随机选 K 个点作为初始中心
  2. 分配:每个样本归到最近的中心(用欧氏距离)
  3. 更新:重新计算每个簇的新中心(均值)
  4. 重复 2~3,直到中心不再变化或达到最大迭代次数

距离度量:默认使用欧氏距离

dist(x,c)=i=1d(xici)2\text{dist}(x, c) = \sqrt{\sum_{i=1}^d (x_i - c_i)^2}

❓ 如何选择 K 值?——两大经典方法

方法1:肘部法则(Elbow Method)
  • 计算不同 K 下的簇内平方和(WCSS):
    WCSS=k=1KxCkxμk2\text{WCSS} = \sum_{k=1}^K \sum_{x \in C_k} \|x - \mu_k\|^2
  • WCSS 随 K 增大而减小
  • 找“拐点”(像手肘)——再增加 K,WCSS 下降变缓
方法2:轮廓系数(Silhouette Coefficient)
  • 衡量样本与其所在簇的相似度 vs 与其他簇的不相似度

  • 取值范围:[-1, 1],越接近1越好

  • 公式:

    s(i)=b(i)a(i)max(a(i),b(i))s(i) = \frac{b(i) - a(i)}{\max(a(i), b(i))}
    • a(i)a(i):样本 i 到同簇其他点的平均距离
    • b(i)b(i):样本 i 到最近其他簇的平均距离

💡 推荐:优先看轮廓系数,更可靠!


🧪 K-Means 代码实现

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score

# 生成模拟数据
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=1.0, random_state=42)

# 肘部法则选K
wcss = []
sil_scores = []
K_range = range(2, 10)
for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(X)
    wcss.append(kmeans.inertia_)  # WCSS
    sil_scores.append(silhouette_score(X, kmeans.labels_))

# 可视化
fig, ax = plt.subplots(1, 2, figsize=(12, 4))

ax[0].plot(K_range, wcss, 'bo-')
ax[0].set_title('肘部法则')
ax[0].set_xlabel('K')
ax[0].set_ylabel('WCSS')

ax[1].plot(K_range, sil_scores, 'ro-')
ax[1].set_title('轮廓系数')
ax[1].set_xlabel('K')
ax[1].set_ylabel('Silhouette Score')

plt.show()

# 最终聚类(假设选K=4)
kmeans = KMeans(n_clusters=4, random_state=42)
y_pred = kmeans.fit_predict(X)

plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='viridis', s=30)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], 
            c='red', marker='x', s=200, linewidths=3)
plt.title("K-Means 聚类结果 (K=4)")
plt.show()

9.2 层次聚类(Hierarchical Clustering)

🌳 核心思想:构建“族谱树”

不像 K-Means 需要预先指定 K,层次聚类会生成一棵树状图(Dendrogram),你可以在任意高度切一刀得到想要的簇数。


两种方式:

类型过程特点
凝聚式(Agglomerative)自底向上:每个点是一簇 → 逐步合并最相似的两簇✅ 常用,适合中小数据
分裂式(Divisive)自顶向下:所有点是一簇 → 逐步分裂❌ 计算复杂,少用

🔍 距离度量(簇间距离)

  • 单链接(Single Linkage):两簇中最近两点的距离 → 易产生“链式效应”
  • 全链接(Complete Linkage):两簇中最远两点的距离 → 簇更紧凑
  • 平均链接(Average Linkage):所有点对的平均距离 → 平衡
  • Ward 法:合并后WCSS增加最小 → 类似K-Means,推荐!

🧪 层次聚类代码

from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.cluster import AgglomerativeClustering

# 凝聚式层次聚类
linked = linkage(X, method='ward')  # Ward法

# 绘制树状图
plt.figure(figsize=(10, 5))
dendrogram(linked, truncate_mode='level', p=5)  # 只显示最后5层
plt.title("层次聚类树状图")
plt.xlabel("样本/簇")
plt.ylabel("距离")
plt.show()

# 指定K=4进行聚类
hac = AgglomerativeClustering(n_clusters=4, linkage='ward')
y_hac = hac.fit_predict(X)

plt.scatter(X[:, 0], X[:, 1], c=y_hac, cmap='plasma', s=30)
plt.title("层次聚类结果 (K=4)")
plt.show()

9.3 DBSCAN 聚类(基于密度)

⚡ 核心思想:找“人多的地方”,忽略“孤魂野鬼”

K-Means 假设簇是球形的,但现实数据可能有任意形状(如月牙、环形)。 DBSCAN 通过密度发现任意形状的簇,并自动识别噪声点


🔑 四大核心概念

概念定义
ε 邻域(Epsilon Neighborhood)以点为中心、半径 ε 的圆内所有点
核心点(Core Point)ε 邻域内至少有 MinPts 个点(包括自己)
边界点(Border Point)在某核心点的 ε 邻域内,但自身不是核心点
噪声点(Noise Point)既不是核心点,也不在任何核心点邻域内

优点

  • 无需指定簇数量
  • 能发现任意形状簇
  • 自动剔除噪声

缺点

  • 对参数 ε 和 MinPts 敏感
  • 密度差异大的数据效果差

🧪 DBSCAN 代码

from sklearn.cluster import DBSCAN

# DBSCAN聚类
dbscan = DBSCAN(eps=1.5, min_samples=5)
y_db = dbscan.fit_predict(X_with_outliers)  # 使用前面加了异常点的数据

# 可视化
plt.scatter(X_with_outliers[y_db != -1, 0], X_with_outliers[y_db != -1, 1], 
            c=y_db[y_db != -1], cmap='Set1', s=30, label='正常簇')
plt.scatter(X_with_outliers[y_db == -1, 0], X_with_outliers[y_db == -1, 1], 
            c='black', marker='x', s=100, label='噪声点')
plt.title("DBSCAN 聚类结果")
plt.legend()
plt.show()

print(f"发现 {len(set(y_db)) - (1 if -1 in y_db else 0)} 个簇")
print(f"噪声点数量: {list(y_db).count(-1)}")

9.4 聚类评估指标

📌 注意:无监督学习没有真实标签,所以不能用准确率!只能用内部指标(仅基于数据和聚类结果)

指标公式思想越好方向特点
轮廓系数(Silhouette)群内紧密 vs 群间分离越大越好(max=1)直观,推荐首选
Calinski-Harabasz(CH)簇间离散 / 簇内离散越大越好计算快,适合凸形簇
Davies-Bouldin(DB)平均簇内距 / 簇间距越小越好对K-Means友好
from sklearn.metrics import calinski_harabasz_score, davies_bouldin_score

labels = kmeans.labels_

print("轮廓系数:", silhouette_score(X, labels))
print("CH指数:", calinski_harabasz_score(X, labels))
print("DB指数:", davies_bouldin_score(X, labels))

9.5 实战案例

案例1:K-Means 用户分群(电商场景)

# 模拟用户数据:年消费、访问频率、平均订单金额
np.random.seed(42)
users = np.random.rand(500, 3)
users[:, 0] *= 10000   # 年消费:0~10000元
users[:, 1] *= 50      # 访问频率:0~50次/月
users[:, 2] *= 500     # 平均订单:0~500元

# 标准化(K-Means对尺度敏感!)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
users_scaled = scaler.fit_transform(users)

# 聚类
kmeans = KMeans(n_clusters=3, random_state=42)
user_clusters = kmeans.fit_predict(users_scaled)

# 分析各群特征
import pandas as pd
df = pd.DataFrame(users, columns=['年消费', '访问频率', '平均订单'])
df['群组'] = user_clusters

print(df.groupby('群组').mean())

输出示例:

年消费    访问频率    平均订单
群组                        
0      8500.2     45.1      420.3    高价值用户
1      1200.5     10.2       80.1    普通用户
2      5000.8     30.5      200.7    中等活跃用户

案例2:DBSCAN 异常交易检测

# 模拟交易数据:金额、时间(小时)、地点(经纬度简化)
transactions = np.random.randn(1000, 3)
transactions[:, 0] = np.abs(transactions[:, 0]) * 1000  # 金额 >0
transactions[:, 1] = (transactions[:, 1] + 12) % 24     # 时间 0-24

# 加入异常交易:深夜大额
anomalies = np.array([[15000, 3, 0.5], [20000, 2, -0.8]])
transactions_full = np.vstack([transactions, anomalies])

# DBSCAN检测
dbscan = DBSCAN(eps=2.0, min_samples=10)
labels = dbscan.fit_predict(transactions_full)

# 输出异常交易
anomaly_indices = np.where(labels == -1)[0]
print("检测到异常交易:")
for idx in anomaly_indices:
    amt, hour, loc = transactions_full[idx]
    print(f"  金额: ¥{amt:.0f}, 时间: {hour:.1f}点, 位置特征: {loc:.2f}")

🎯 本章总结:三大聚类算法对比

算法是否需指定K簇形状噪声处理速度适用场景
K-Means✅ 是球形❌ 不能⭐⭐⭐⭐用户分群、快速原型
层次聚类❌ 否(可后选)球形❌ 不能⭐⭐小数据、需要树状结构
DBSCAN❌ 否任意✅ 自动识别⭐⭐⭐异常检测、非球形簇

💡 建议

  • 先试 K-Means(快、简单)
  • 如果簇形状奇怪 → 用 DBSCAN
  • 数据量小且想探索层次关系 → 用 层次聚类

资料关注

公众号:咚咚王 gitee:gitee.com/wy185850518…

《Python编程:从入门到实践》 《利用Python进行数据分析》 《算法导论中文第三版》 《概率论与数理统计(第四版) (盛骤) 》 《程序员的数学》 《线性代数应该这样学第3版》 《微积分和数学分析引论》 《(西瓜书)周志华-机器学习》 《TensorFlow机器学习实战指南》 《Sklearn与TensorFlow机器学习实用指南》 《模式识别(第四版)》 《深度学习 deep learning》伊恩·古德费洛著 花书 《Python深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》 《深入浅出神经网络与深度学习+(迈克尔·尼尔森(Michael+Nielsen)》 《自然语言处理综论 第2版》 《Natural-Language-Processing-with-PyTorch》 《计算机视觉-算法与应用(中文版)》 《Learning OpenCV 4》 《AIGC:智能创作时代》杜雨+&+张孜铭 《AIGC原理与实践:零基础学大语言模型、扩散模型和多模态模型》 《从零构建大语言模型(中文版)》 《实战AI大模型》 《AI 3.0》