机器学习 - 聚类算法

聚类算法概述

聚类是一种无监督学习方法,用于将数据集划分成若干个组(簇),使得同一簇内的数据点之间的相似度尽可能高,而不同簇之间的相似度尽可能低。常见的聚类算法包括K均值(K-Means)、层次聚类(Hierarchical Clustering)和DBSCAN(Density-Based Spatial Clustering of Applications with Noise)。

1. K均值聚类(K-Means Clustering)

K均值是一种迭代的聚类算法,目标是将数据集分为K个簇,使得簇内数据点的总方差(即距离平方和)最小。其步骤如下:

  1. 随机选择K个初始质心(Centroid)。
  2. 将每个数据点分配给距离最近的质心,形成K个簇。
  3. 计算每个簇的质心(即簇内所有数据点的平均值)。
  4. 重复步骤2和3,直到质心不再变化或达到最大迭代次数。
K均值算法的数学描述
  1. 初始化质心: μ 1 , μ 2 , … , μ K \mu_1, \mu_2, \ldots, \mu_K μ1,μ2,,μK
  2. 对于每个数据点 xi,计算其到每个质心的距离,并分配给最近的质心:

c i = arg ⁡ min ⁡ j ∥ x i − μ j ∥ 2 c_i = \arg\min_{j} \| x_i - \mu_j \|^2 ci=argjminxiμj2

  1. 重新计算质心:

μ j = 1 ∣ C j ∣ ∑ x i ∈ C j x i \mu_j = \frac{1}{|C_j|} \sum_{x_i \in C_j} x_i μj=Cj1xiCjxi

其中, Cj 是第 j 个簇的所有数据点集合。

Python实现案例
from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pyplot as plt

# 生成示例数据
np.random.seed(42)
X = np.random.rand(100, 2)

# K均值聚类
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)

# 绘制聚类结果
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.75)
plt.show()

2. 层次聚类(Hierarchical Clustering)

层次聚类是一种基于树形结构的聚类方法,主要分为两种:凝聚层次聚类(Agglomerative Clustering)和分裂层次聚类(Divisive Clustering)。凝聚层次聚类从每个数据点开始,每次合并最相似的簇,直到所有点都在一个簇内;而分裂层次聚类则从一个大簇开始,每次将最不相似的簇分开,直到每个点成为一个簇。

距离计算方法
  1. 单链接(Single Linkage):最短距离
    d single ( C i , C j ) = min ⁡ x ∈ C i , y ∈ C j ∥ x − y ∥ d_{\text{single}}(C_i, C_j) = \min_{x \in C_i, y \in C_j} \|x - y\| dsingle(Ci,Cj)=xCi,yCjminxy

  2. 全链接(Complete Linkage):最长距离
    d complete ( C i , C j ) = max ⁡ x ∈ C i , y ∈ C j ∥ x − y ∥ d_{\text{complete}}(C_i, C_j) = \max_{x \in C_i, y \in C_j} \|x - y\| dcomplete(Ci,Cj)=xCi,yCjmaxxy

  3. 平均链接(Average Linkage):平均距离
    d average ( C i , C j ) = 1 ∣ C i ∣ ∣ C j ∣ ∑ x ∈ C i ∑ y ∈ C j ∥ x − y ∥ d_{\text{average}}(C_i, C_j) = \frac{1}{|C_i||C_j|} \sum_{x \in C_i} \sum_{y \in C_j} \|x - y\| daverage(Ci,Cj)=Ci∣∣Cj1xCiyCjxy

Python实现案例
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

# 生成示例数据
X, y = make_blobs(n_samples=50, centers=3, random_state=42)

# 层次聚类
Z = linkage(X, 'ward')

# 绘制树状图
plt.figure(figsize=(10, 7))
dendrogram(Z)
plt.show()

3. DBSCAN(Density-Based Spatial Clustering of Applications with Noise)

DBSCAN是一种基于密度的聚类方法,能够有效处理噪声和发现任意形状的簇。其主要思想是通过两个参数:最小样本数(minPts)和半径(ε),来定义簇的密度。

DBSCAN算法步骤
  1. 对于每个数据点,计算其ε邻域内的点的数量。
  2. 如果ε邻域内的点的数量大于或等于minPts,则将该点标记为核心点,并将其ε邻域内的所有点标记为同一簇。
  3. 对于非核心点,如果其ε邻域内包含至少一个核心点,则将其分配到该核心点所在的簇,否则标记为噪声点。
Python实现案例
from sklearn.cluster import DBSCAN
import numpy as np
import matplotlib.pyplot as plt

# 生成示例数据
np.random.seed(42)
X = np.random.rand(100, 2)

# DBSCAN聚类
db = DBSCAN(eps=0.1, min_samples=5).fit(X)
labels = db.labels_

# 绘制聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.show()

聚类算法的评估方法

1. 轮廓系数(Silhouette Coefficient)

轮廓系数用于评估单个数据点的聚类质量,取值范围为[-1, 1]。对于数据点 i ,定义如下:

s ( i ) = b ( i ) − a ( i ) max ⁡ ( a ( i ) , b ( i ) ) s(i) = \frac{b(i) - a(i)}{\max(a(i), b(i))} s(i)=max(a(i),b(i))b(i)a(i)

其中, a(i) 是数据点 i 到其簇内其他点的平均距离, b(i) 是数据点 i 到最近的其他簇的平均距离。

计算示例
from sklearn.metrics import silhouette_score

# 计算轮廓系数
score = silhouette_score(X, y_kmeans)
print(f'Silhouette Score: {score}')

2. Davies-Bouldin指数(Davies-Bouldin Index)

Davies-Bouldin指数用于评估聚类的紧密性和分离度,值越小表示聚类效果越好。定义如下:

D B = 1 K ∑ i = 1 K max ⁡ j ≠ i ( σ i + σ j d ( μ i , μ j ) ) DB = \frac{1}{K} \sum_{i=1}^{K} \max_{j \ne i} \left( \frac{\sigma_i + \sigma_j}{d(\mu_i, \mu_j)} \right) DB=K1i=1Kj=imax(d(μi,μj)σi+σj)

其中, \sigmai 是第 i 个簇内的数据点到质心的平均距离, d ( μ i , μ j ) d(\mu_i, \mu_j) d(μi,μj)是簇 i 和簇 j 的质心之间的距离。

计算示例
from sklearn.metrics import davies_bouldin_score

# 计算Davies-Bouldin指数
db_index = davies_bouldin_score(X, y_kmeans)
print(f'Davies-Bouldin Index: {db_index}')

3. Calinski-Harabasz指数(Calinski-Harabasz Index)

Calinski-Harabasz指数(或方差比准则)用于评估聚类的紧密性和分离度,值越大表示聚类效果越好。定义如下:

C H = tr ( B k ) / ( K − 1 ) tr ( W k ) / ( n − K ) CH = \frac{ \text{tr}(B_k) / (K - 1) }{ \text{tr}(W_k) / (n - K) } CH=tr(Wk)/(nK)tr(Bk)/(K1)

其中, tr ( B k ) \text{tr}(B_k) tr(Bk)是簇间离散度矩阵的迹, tr ( W k ) \text{tr}(W_k) tr(Wk)是簇内离散度矩阵的迹, K 是簇的数量, n 是数据点的数量。

下面我们详细推导这一指标。

类内散度矩阵(Within-cluster scatter matrix)

类内散度矩阵 Wk 定义为每个簇内的样本点到该簇质心(centroid)的平方欧氏距离之和。对于第 i 个簇,类内散度矩阵 Wi 定义如下:

W i = ∑ x ∈ C i ( x − c i ) ( x − c i ) T W_i = \sum_{x \in C_i} (x - c_i)(x - c_i)^T Wi=xCi(xci)(xci)T

其中:

  • ( Ci ) 是第 ( i ) 个簇的样本集合。
  • ( ci ) 是第 ( i ) 个簇的质心。

类内散度矩阵 ( W_k ) 是所有簇的类内散度矩阵之和:

[ W_k = \sum_{i=1}^{k} W_i ]

类间散度矩阵(Between-cluster scatter matrix)

类间散度矩阵 ( Bk ) 定义为各簇质心到所有样本点的整体质心的平方欧氏距离之和。整体质心 ( c ) 是所有样本点的平均值:

c = 1 N ∑ i = 1 N x i c = \frac{1}{N} \sum_{i=1}^{N} x_i c=N1i=1Nxi

类间散度矩阵 ( Bk ) 定义如下:

B k = ∑ i = 1 k n i ( c i − c ) ( c i − c ) T B_k = \sum_{i=1}^{k} n_i (c_i - c)(c_i - c)^T Bk=i=1kni(cic)(cic)T

其中:

  • ( ni ) 是第 ( i ) 个簇中的样本数量。

迹(Trace)

矩阵的迹是指矩阵主对角线元素之和。对于类内散度矩阵 ( Wk ) 和类间散度矩阵 ( Bk ) 的迹分别为:

Tr ( W k ) = ∑ i = 1 k ∑ x ∈ C i ∥ x − c i ∥ 2 \text{Tr}(W_k) = \sum_{i=1}^{k} \sum_{x \in C_i} \|x - c_i\|^2 Tr(Wk)=i=1kxCixci2
Tr ( B k ) = ∑ i = 1 k n i ∥ c i − c ∥ 2 \text{Tr}(B_k) = \sum_{i=1}^{k} n_i \|c_i - c\|^2 Tr(Bk)=i=1knicic2

Calinski-Harabasz Score的计算

根据以上定义和公式,CH Score的计算公式为:

CH Score = Tr ( B k ) Tr ( W k ) × N − k k − 1 \text{CH Score} = \frac{\text{Tr}(B_k)}{\text{Tr}(W_k)} \times \frac{N - k}{k - 1} CH Score=Tr(Wk)Tr(Bk)×k1Nk

其中:

  • Tr ( B k ) \text{Tr}(B_k) Tr(Bk) 表示各簇之间的离散度
  • Tr ( W k ) \text{Tr}(W_k) Tr(Wk) 表示各簇内部的紧密度
  • N − k k − 1 \frac{N - k}{k - 1} k1Nk 是一个标准化因子,用于调整不同聚类数的影响

Calinski-Harabasz Score通过比较类间距离和类内距离来评估聚类的效果,得分越高,表示聚类效果越好,即簇内数据越紧密,簇间数据越分散。这一指标在聚类分析中常用于选择最优聚类数。

计算示例
from sklearn.metrics import calinski_harabasz_score

# 计算Calinski-Harabasz指数
ch_index = calinski_harabasz_score(X, y_kmeans)
print(f'Calinski-Harabasz Index: {ch_index}')

4. 简单实现案例

结合上述所有内容,以下是一个完整的示例代码,用于生成数据、进行聚类并评估聚类效果:

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score, davies_bouldin_score, calinski_harabasz_score
import matplotlib.pyplot as plt

# 生成示例数据
X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=42)

# K均值聚类
k

means = KMeans(n_clusters=4, random_state=42)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)

# 评估聚类效果
sil_score = silhouette_score(X, y_kmeans)
db_score = davies_bouldin_score(X, y_kmeans)
ch_score = calinski_harabasz_score(X, y_kmeans)

print(f'Silhouette Score: {sil_score}')
print(f'Davies-Bouldin Index: {db_score}')
print(f'Calinski-Harabasz Index: {ch_score}')

# 绘制聚类结果
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.75)
plt.show()

常见问题

1. 选择合适的聚类算法

问题:如何选择合适的聚类算法?
解决方案

  • 数据量较大且簇的形状较规则时,选择K均值(K-Means)。
  • 需要处理噪声和发现任意形状的簇时,选择DBSCAN。
  • 需要层次化展示簇时,选择层次聚类(Hierarchical Clustering)。
  • 可以通过尝试不同的算法,并使用评估指标(如轮廓系数、Davies-Bouldin指数等)来比较不同算法的效果。

2. 确定聚类数目(K值)

问题:如何确定K均值中的K值?
解决方案

  • 使用肘部法则(Elbow Method):绘制K值与聚类总误差平方和(Sum of Squared Errors, SSE)的图,选择“SSE陡降后逐渐平缓”的拐点处。
  • 使用轮廓系数(Silhouette Coefficient):尝试不同的K值,选择轮廓系数最高的K值。
  • 使用Calinski-Harabasz指数:选择Calinski-Harabasz指数最高的K值。

3. 处理异常点和噪声

问题:如何处理数据中的异常点和噪声?
解决方案

  • 使用DBSCAN,可以有效识别并处理噪声点。
  • 对数据进行预处理,删除或修正明显的异常点。
  • 使用鲁棒的聚类算法,如均值漂移(Mean Shift)。

4. 数据标准化

问题:是否需要对数据进行标准化?
解决方案

  • 通常需要对数据进行标准化,特别是当数据具有不同的量纲和单位时。
  • 可以使用标准化(StandardScaler)或归一化(MinMaxScaler)等方法。

5. 高维数据处理

问题:如何处理高维数据?
解决方案

  • 使用降维技术,如主成分分析(PCA)或t-SNE,将数据降维到2D或3D进行可视化。
  • 使用核方法(如核PCA)保留非线性结构。
  • 使用高维聚类算法,如谱聚类(Spectral Clustering)。

6. 聚类结果的不稳定性

问题:聚类结果不稳定,如何解决?
解决方案

  • 对初始质心进行多次随机选择,取平均结果。
  • 使用聚类结果的可视化(如t-SNE)观察结果的稳定性。
  • 使用稳健的初始化方法(如k-means++)。

7. 聚类结果的解释性

问题:如何解释聚类结果?
解决方案

  • 对每个簇内的特征进行统计分析(如均值、方差等),找出每个簇的特征模式。
  • 使用决策树等方法对聚类结果进行解释。
  • 可视化簇的中心和边界,帮助理解聚类结果。

8. 处理类别不平衡

问题:如何处理类别不平衡的问题?
解决方案

  • 在聚类前对数据进行采样(如过采样或欠采样)以平衡类别。
  • 使用加权聚类方法,对少数类赋予更高的权重。
  • 使用适应性方法,根据类别分布调整算法参数。

9. 评估聚类效果

问题:如何评估聚类效果?
解决方案

  • 使用内在评估指标,如轮廓系数、Davies-Bouldin指数、Calinski-Harabasz指数等。
  • 使用外在评估指标(如果有真实标签),如Rand指数、调整兰德指数(Adjusted Rand Index, ARI)等。
  • 可视化聚类结果,观察聚类效果。

10. 大规模数据聚类

问题:如何处理大规模数据的聚类?
解决方案

  • 使用Mini-Batch K均值算法,对大规模数据进行小批量迭代更新。
  • 使用分布式聚类算法(如Apache Spark中的MLlib库)。
  • 对数据进行采样,先在小规模数据上聚类,再扩展到全数据集。

示例代码实现案例

下面是一些示例代码,展示如何解决上述部分问题:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score, calinski_harabasz_score

# 生成示例数据
X, _ = make_blobs(n_samples=1000, centers=4, cluster_std=0.60, random_state=42)

# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 确定K值(肘部法)
sse = []
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(X_scaled)
    sse.append(kmeans.inertia_)

plt.plot(range(1, 11), sse, marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('SSE')
plt.show()

# K均值聚类
kmeans = KMeans(n_clusters=4, random_state=42)
kmeans.fit(X_scaled)
y_kmeans = kmeans.predict(X_scaled)

# DBSCAN聚类
dbscan = DBSCAN(eps=0.3, min_samples=5)
y_dbscan = dbscan.fit_predict(X_scaled)

# 评估聚类效果
silhouette_kmeans = silhouette_score(X_scaled, y_kmeans)
ch_kmeans = calinski_harabasz_score(X_scaled, y_kmeans)

print(f'Silhouette Score (K-Means): {silhouette_kmeans}')
print(f'Calinski-Harabasz Index (K-Means): {ch_kmeans}')

# 绘制K均值聚类结果
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=y_kmeans, cmap='viridis', s=50)
plt.title('K-Means Clustering')
plt.show()

# 绘制DBSCAN聚类结果
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=y_dbscan, cmap='viridis', s=50)
plt.title('DBSCAN Clustering')
plt.show()

以上代码展示了如何标准化数据、确定K值、执行K均值和DBSCAN聚类,并评估聚类效果。这些步骤和技术可以帮助解决许多常见的聚类问题。

更多问题咨询

Cos机器人

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值