1. 概述

聚类(Clustering)是将数据集划分为若干**簇(Cluster)**的无监督学习任务,使得:

  • 同一簇内的样本相似度高
  • 不同簇之间的样本相似度低

1.1 聚类 vs 分类

方面聚类分类
学习方式无监督有监督
标签不需要需要
目标发现数据内在结构预测已知类别
评估方式内部/外部指标准确率等

1.2 距离度量

聚类算法中常用的距离度量包括:

距离公式适用场景
欧氏距离连续特征
曼哈顿距离$d(x, y) = \sum_ix_i - y_i
余弦相似度文本向量
马氏距离相关特征

2. K-Means算法

2.1 算法描述

K-Means将数据划分为个簇,目标是最小化簇内平方和(Within-Cluster Sum of Squares, WCSS)

其中 是簇 的质心(均值)。

2.2 算法流程

输入:数据集 X,聚类数 K
输出:K 个簇

1. 随机选择 K 个样本作为初始质心 μ_1, ..., μ_K
2. 重复直到收敛:
   a. 分配阶段:对于每个样本 x_i,将其分配给最近的质心
      C_k = {x_i : ||x_i - μ_k|| ≤ ||x_i - μ_j||, ∀j ≠ k}
   b. 更新阶段:重新计算每个簇的质心
      μ_k = (1/|C_k|) * Σ_{x ∈ C_k} x
3. 返回簇划分

2.3 算法图示

初始状态:                    迭代1:
   ·   ·                      ● ● ●
      K1   ·                  ● ● ● ●
   ·        · K2      →        ● ● ●
      ·   ·                  ● ● ●
         ·                   K1  K2  K3
   K3    ·   ·
                       
迭代2:                      收敛:
   ● ● ●                      ●●●●●
   ● ● ● ●                   ●●●●●
   ● ● ●                      ●●●●●
   K1  K2  K3                 K1  K2  K3

2.4 K-Means++初始化

K-Means++通过智能初始化改善聚类质量:

1. 随机选择第一个质心 μ_1
2. 对于每个样本 x,计算 D(x) = min_j ||x - μ_j||²
3. 以概率 P(x) = D(x) / Σ D(x) 选择下一个质心
4. 重复直到选择 K 个质心

K-Means++的优势:

  • 质心更分散,减少陷入局部最优的可能
  • 理论上,K-Means++的期望误差是O(log K)倍的OPT

2.5 Mini-Batch K-Means

对于大规模数据集,使用**小批量(Mini-Batch)**进行优化:

from sklearn.cluster import MiniBatchKMeans
import numpy as np
 
# 生成大规模数据
X = np.random.rand(100000, 10)
 
# Mini-Batch K-Means
mbkm = MiniBatchKMeans(n_clusters=100, batch_size=1000, random_state=42)
mbkm.fit(X)

2.6 K值选择

肘部法(Elbow Method)

绘制WCSS随K变化的曲线,选择”肘部”位置:

import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
 
wcss = []
K_range = range(1, 11)
 
for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(X)
    wcss.append(kmeans.inertia_)
 
plt.plot(K_range, wcss, 'bo-')
plt.xlabel('Number of clusters (K)')
plt.ylabel('WCSS')
plt.title('Elbow Method')
plt.show()

轮廓系数(Silhouette Score)

其中 是样本与同簇其他样本的平均距离, 是样本与最近邻簇的平均距离。轮廓系数范围为[-1, 1],越接近1越好。

from sklearn.metrics import silhouette_score
 
silhouette_scores = []
for k in range(2, 11):
    kmeans = KMeans(n_clusters=k, random_state=42)
    labels = kmeans.fit_predict(X)
    score = silhouette_score(X, labels)
    silhouette_scores.append(score)
 
print(f"Best K: {range(2, 11)[np.argmax(silhouette_scores)]}")

3. 层次聚类

3.1 算法类型

类型策略特点
凝聚式(Agglomerative)自底向上从N个单点簇开始,逐步合并
分裂式(Divisive)自顶向下从1个包含所有点的簇开始,逐步分裂

3.2 簇间距离度量

方法公式特点
最近邻(Single Linkage)容易产生链式效应
最远邻(Complete Linkage)趋向于形成紧凑簇
平均距离(Average Linkage)$\frac{1}{C_i
Ward距离$\Delta(C_i, C_j) = \frac{C_i

3.3 算法流程

输入:数据集 X,距离阈值 d
输出:层次聚类树(树状图)

1. 每个样本作为一个初始簇
2. 计算所有簇对之间的距离
3. 合并距离最近的两个簇
4. 更新距离矩阵
5. 重复步骤3-4,直到只剩一个簇或达到阈值

3.4 树状图(Dendrogram)

from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
 
# 生成数据
from sklearn.datasets import make_blobs
X, _ = make_blobs(n_samples=50, centers=3, random_state=42)
 
# 层次聚类
Z = linkage(X, method='ward')
 
# 绘制树状图
plt.figure(figsize=(10, 6))
dendrogram(Z)
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Sample Index')
plt.ylabel('Distance')
plt.show()

4. DBSCAN

4.1 算法思想

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)基于密度进行聚类,可以发现任意形状的簇,并自动识别噪声点。

4.2 核心概念

  • -邻域:样本 邻域是距离 不超过 的样本集合
  • 核心点(Core Point):邻域内样本数不少于 MinPts 的点
  • 边界点(Border Point):在某个核心点的邻域内,但自身不是核心点
  • 噪声点(Noise Point):既不是核心点也不是边界点
        ●                    ●
    ●   ●                ●   ●
        ●       →           ●  ← 核心点 (MinPts=4)
    ●   ●                ●   ●
    ●       ●           ●       ← 边界点
                        ○  ← 噪声点

4.3 算法流程

输入:数据集 X,邻域半径 ε,密度阈值 MinPts
输出:簇标签

1. 将所有点标记为未访问
2. 随机选择一个未访问点 p
3. 标记 p 为已访问
4. 如果 p 的 ε-邻域至少有 MinPts 个点:
   a. 创建一个新簇 C,将 p 加入 C
   b. 创建一个种子集合 N,包含 p 的 ε-邻域中的所有点
   c. 对 N 中的每个点 q:
      - 如果 q 未被访问,标记为已访问
      - 如果 q 的 ε-邻域至少有 MinPts 个点,将这些点加入 N
      - 如果 q 不属于任何簇,将 q 加入簇 C
5. 否则,标记 p 为噪声点
6. 重复直到所有点都被访问

4.4 参数选择

的选择

使用K-距离图:计算每个点到第k个最近邻的距离,绘制排序后的距离图,选择”肘部”对应的距离。

from sklearn.neighbors import NearestNeighbors
import numpy as np
 
X = np.random.rand(500, 2)
 
# 计算k-距离
k = 5
nbrs = NearestNeighbors(n_neighbors=k).fit(X)
distances, indices = nbrs.kneighbors(X)
 
# 排序并绘图
k_distances = np.sort(distances[:, k-1])
plt.plot(k_distances)
plt.xlabel('Points sorted by distance')
plt.ylabel(f'{k}-th Nearest Neighbor Distance')
plt.show()

MinPts 的选择

  • 数据集维度 d:通常取
  • 经验法则:
  • 或者使用领域知识确定

4.5 DBSCAN的优缺点

优点缺点
可以发现任意形状的簇对参数敏感
可以识别噪声点在密度不均匀的数据集上效果差
不需要指定簇数高维数据上距离度量可能失效
对异常值鲁棒计算复杂度较高

5. 谱聚类

5.1 算法思想

谱聚类(Spectral Clustering)使用数据的图表示,通过拉普拉斯矩阵的特征向量进行降维,然后使用K-Means进行聚类。

5.2 相似图构建

  • ε-邻域图:连接距离小于ε的点
  • K近邻图:只连接每个点的K个最近邻
  • 全连接图:使用高斯核

5.3 拉普拉斯矩阵

  • 非归一化拉普拉斯矩阵
  • 归一化拉普拉斯矩阵

其中 是度矩阵, 是相似度矩阵。

5.4 算法流程

输入:数据集 X,聚类数 K
输出:K 个簇

1. 构建相似度矩阵 W
2. 计算度矩阵 D 和拉普拉斯矩阵 L
3. 计算 L 的前 K 个最小特征值对应的特征向量
4. 将特征向量组成矩阵 U (N × K)
5. 对 U 的行进行归一化得到 Z
6. 使用 K-Means 对 Z 进行聚类

5.5 代码实现

import numpy as np
from sklearn.cluster import KMeans
 
def spectral_clustering(X, n_clusters, sigma=1.0):
    # 构建相似度矩阵
    n = X.shape[0]
    W = np.zeros((n, n))
    for i in range(n):
        diff = X - X[i]
        W[i] = np.exp(-np.sum(diff**2, axis=1) / (2 * sigma**2))
    
    # 度矩阵
    D = np.diag(W.sum(axis=1))
    
    # 归一化拉普拉斯矩阵
    D_inv_sqrt = np.diag(1.0 / np.sqrt(np.diag(D)))
    L = np.eye(n) - D_inv_sqrt @ W @ D_inv_sqrt
    
    # 特征向量
    eigvals, eigvecs = np.linalg.eigh(L)
    U = eigvecs[:, :n_clusters]
    
    # 归一化
    Z = U / np.linalg.norm(U, axis=1, keepdims=True)
    
    # K-Means聚类
    kmeans = KMeans(n_clusters=n_clusters, random_state=42)
    return kmeans.fit_predict(Z)

6. 高斯混合模型(GMM)

6.1 模型定义

高斯混合模型假设数据由 个高斯分布混合而成:

其中 是混合系数, 是高斯分布。

6.2 EM算法求解

E步:计算每个样本属于各簇的后验概率:

M步:更新参数:

6.3 代码实现

from sklearn.mixture import GaussianMixture
import numpy as np
 
# 生成数据
from sklearn.datasets import make_blobs
X, _ = make_blobs(n_samples=500, centers=3, random_state=42)
 
# GMM聚类
gmm = GaussianMixture(n_components=3, covariance_type='full', random_state=42)
labels = gmm.fit_predict(X)
 
# 预测概率
probs = gmm.predict_proba(X)
print(f"Cluster probabilities for first sample: {probs[0]}")

7. 聚类评估指标

7.1 内部指标

指标定义范围方向
轮廓系数[-1, 1]越大越好
CH指数[0, +∞)越大越好
DB指数[0, +∞)越小越好

其中 是簇间平方和, 是簇内平方和。

7.2 外部指标(当有真实标签时)

指标说明
调整兰德指数 (ARI)范围[-1,1],1表示完美匹配
归一化互信息 (NMI)范围[0,1],1表示完美匹配
Fowlkes-Mallows Index精确率和召回率的几何平均
from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score
 
# 真实标签
y_true = np.array([0, 0, 1, 1, 2, 2])
 
# 聚类结果
y_pred = np.array([0, 0, 1, 1, 2, 1])
 
print(f"ARI: {adjusted_rand_score(y_true, y_pred):.4f}")
print(f"NMI: {normalized_mutual_info_score(y_true, y_pred):.4f}")

8. 算法选择指南

数据特点推荐算法
大规模数据Mini-Batch K-Means
簇大小不均DBSCAN, 谱聚类
任意形状簇DBSCAN, 谱聚类, GMM
高维数据HDBSCAN, 谱聚类
只需少量超参数K-Means++
需要层次结构层次聚类
概率簇成员GMM

9. 应用场景

9.1 客户细分

将客户按行为特征聚类,进行精准营销。

9.2 图像分割

将图像像素按颜色、纹理等特征聚类,实现分割。

9.3 异常检测

将正常数据聚类,落在稀疏区域的点视为异常。

9.4 文本主题发现

将文档按主题聚类,发现潜在主题。

参考资料