数学建模学习-聚类分析(Cluster Analysis)教程(13)
写在最前
注意本文的相关代码及例子为同学们提供参考,借鉴相关结构,在这里举一些通俗易懂的例子,方便同学们根据实际情况修改代码,很多同学私信反映能否添加一些可视化,这里每篇教程都尽可能增加一些可视化方便同学理解,但具体使用时,同学们要根据实际情况选择是否在论文中添加可视化图片。
系列教程计划持续更新,同学们可以免费订阅专栏,内容充足后专栏可能付费,提前订阅的同学可以免费阅读,同时相关代码获取可以关注博主评论或私信。
目录
算法简介
聚类分析是一种无监督学习方法,其主要目的是将相似的对象分组到同一个簇中,而将不相似的对象分到不同簇中。在数学建模中,聚类分析常用于发现数据中的内在结构和模式,帮助我们理解数据的分布特征。
本教程主要介绍两种常用的聚类方法:
- K-means聚类:基于距离的划分聚类方法
- 层次聚类:基于层次分解的聚类方法
算法特点
K-means聚类特点
- 算法简单,易于实现
- 计算复杂度相对较低,适合处理大规模数据
- 对初始聚类中心的选择敏感
- 需要预先指定聚类数量K
- 对噪声和异常值敏感
- 只能发现球形簇
- 不适合处理非凸形状的簇
层次聚类特点
- 可以得到层次化的聚类结构
- 不需要预先指定聚类数量
- 可以通过树状图直观显示聚类过程
- 计算复杂度较高,不适合大规模数据
- 一旦合并或分裂后不能撤销
- 能够处理任意形状的簇
- 对噪声和异常值较为稳健
数学原理
K-means数学原理
K-means算法的目标是最小化所有点到其所属簇中心的距离平方和,即最小化以下目标函数:
J
=
∑
j
=
1
k
∑
i
=
1
n
∥
x
i
(
j
)
−
c
j
∥
2
J = \sum_{j=1}^k \sum_{i=1}^n \|x_i^{(j)} - c_j\|^2
J=∑j=1k∑i=1n∥xi(j)−cj∥2
其中:
- k k k 是簇的数量
- n n n 是数据点的数量
- x i ( j ) x_i^{(j)} xi(j) 是属于第j个簇的第i个数据点
-
c
j
c_j
cj 是第j个簇的中心点
算法的收敛性可以通过以下定理保证:
- 目标函数J在每次迭代中都会减小
- 由于J有下界(0),算法最终会收敛到局部最优解
层次聚类数学原理
层次聚类中的距离度量方法包括:
- 单链接(Single Linkage):
D ( C i , C j ) = min x ∈ C i , y ∈ C j d ( x , y ) D(C_i, C_j) = \min_{x \in C_i, y \in C_j} d(x,y) D(Ci,Cj)=minx∈Ci,y∈Cjd(x,y) - 全链接(Complete Linkage):
D ( C i , C j ) = max x ∈ C i , y ∈ C j d ( x , y ) D(C_i, C_j) = \max_{x \in C_i, y \in C_j} d(x,y) D(Ci,Cj)=maxx∈Ci,y∈Cjd(x,y) - 平均链接(Average Linkage):
D ( C i , C j ) = 1 ∣ C i ∣ ∣ C j ∣ ∑ x ∈ C i ∑ y ∈ C j d ( x , y ) D(C_i, C_j) = \frac{1}{|C_i||C_j|} \sum_{x \in C_i} \sum_{y \in C_j} d(x,y) D(Ci,Cj)=∣Ci∣∣Cj∣1∑x∈Ci∑y∈Cjd(x,y) - Ward方法:
最小化合并后类内平方和的增量:
Δ ( A , B ) = ∑ i ∈ A ∪ B ∥ x i − m A ∪ B ∥ 2 − ∑ i ∈ A ∥ x i − m A ∥ 2 − ∑ i ∈ B ∥ x i − m B ∥ 2 \Delta(A,B) = \sum_{i \in A \cup B} \|x_i - m_{A \cup B}\|^2 - \sum_{i \in A} \|x_i - m_A\|^2 - \sum_{i \in B} \|x_i - m_B\|^2 Δ(A,B)=∑i∈A∪B∥xi−mA∪B∥2−∑i∈A∥xi−mA∥2−∑i∈B∥xi−mB∥2
应用场景
1. 客户分群
- 根据客户的消费行为、人口统计特征等进行分群
- 制定针对性的营销策略
- 识别高价值客户群体
2. 图像分割
- 医学图像分割
- 遥感图像分析
- 计算机视觉应用
3. 异常检测
- 金融欺诈检测
- 网络入侵检测
- 工业质量控制
4. 文本分析
- 文档聚类
- 主题发现
- 新闻分类
5. 生物信息学
- 基因表达分析
- 蛋白质结构分类
- 疾病亚型识别
环境准备
本教程需要以下Python库:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, AgglomerativeClustering
from sklearn.datasets import make_blobs
import seaborn as sns
from scipy.cluster.hierarchy import dendrogram, linkage
K-means聚类
K-means算法的基本步骤:
- 随机选择K个点作为初始聚类中心
- 计算每个数据点到各个聚类中心的距离,将其划分到最近的聚类中心所属的类
- 重新计算每个类的中心点(均值)
- 重复步骤2和3,直到聚类中心基本不再变化
初始中心点选择策略
- 随机选择
- K-means++算法:
- 随机选择第一个中心点
- 计算每个点到已选中心点的最短距离
- 按距离的平方作为概率选择新的中心点
- 重复直到选择K个中心点
代码实现
def kmeans_clustering(X, n_clusters=4):
"""执行K-means聚类"""
kmeans = KMeans(n_clusters=n_clusters, random_state=0)
y_kmeans = kmeans.fit_predict(X)
# 可视化结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
c='red', marker='x', s=200, linewidths=3, label='聚类中心')
plt.title('K-means聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.legend()
plt.savefig('cluster_analysis_13/images/kmeans_result.png')
plt.close()
K-means聚类结果
层次聚类
层次聚类可以自底向上(凝聚式)或自顶向下(分裂式)进行,本教程采用凝聚式层次聚类。
凝聚式层次聚类步骤
- 将每个数据点视为一个簇
- 计算所有簇对之间的距离
- 合并距离最近的两个簇
- 更新簇间距离
- 重复步骤3和4,直到达到预期的簇数量或所有点都在同一个簇中
代码实现
def hierarchical_clustering(X, n_clusters=4):
"""执行层次聚类"""
# 使用层次聚类
clustering = AgglomerativeClustering(n_clusters=n_clusters)
y_hc = clustering.fit_predict(X)
# 可视化聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y_hc, cmap='viridis')
plt.title('层次聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.savefig('cluster_analysis_13/images/hierarchical_result.png')
plt.close()
# 绘制树状图
plt.figure(figsize=(10, 7))
linkage_matrix = linkage(X, method='ward')
dendrogram(linkage_matrix)
plt.title('层次聚类树状图')
plt.xlabel('样本索引')
plt.ylabel('距离')
plt.savefig('cluster_analysis_13/images/dendrogram.png')
plt.close()
层次聚类结果
层次聚类树状图
聚类评估
在K-means聚类中,我们常用以下方法评估聚类效果:
1. 肘部法则(Elbow Method)
通过计算不同K值下的聚类内平方和(WCSS)来确定最佳的聚类数量。
2. 轮廓系数(Silhouette Coefficient)
衡量簇的紧密度和分离度:
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 ) a(i) a(i) 是点i与同簇其他点的平均距离
- b ( i ) b(i) b(i) 是点i与最近的其他簇中的点的平均距离
3. Calinski-Harabasz指数
计算簇间离散度与簇内离散度的比值:
C
H
=
t
r
(
B
k
)
t
r
(
W
k
)
×
n
−
k
k
−
1
CH = \frac{tr(B_k)}{tr(W_k)} \times \frac{n-k}{k-1}
CH=tr(Wk)tr(Bk)×k−1n−k
代码实现
def evaluate_k_values(X, max_k=10):
"""评估不同K值的聚类效果"""
inertias = []
for k in range(1, max_k + 1):
kmeans = KMeans(n_clusters=k, random_state=0)
kmeans.fit(X)
inertias.append(kmeans.inertia_)
plt.figure(figsize=(10, 6))
plt.plot(range(1, max_k + 1), inertias, 'bo-')
plt.title('肘部法则图')
plt.xlabel('聚类数量 (k)')
plt.ylabel('聚类内平方和 (WCSS)')
plt.savefig('cluster_analysis_13/images/elbow_method.png')
plt.close()
肘部法则结果
实际应用注意事项
1. 数据预处理
- 特征标准化:确保各个特征的尺度一致
- 异常值处理:移除或处理异常值
- 缺失值处理:填充或删除缺失值
2. 特征选择
- 选择有区分度的特征
- 降维处理(如PCA)
- 避免使用相关性过高的特征
3. 聚类数量选择
- 结合业务需求
- 使用多种评估指标
- 考虑计算资源限制
4. 结果验证
- 交叉验证
- 稳定性分析
- 业务解释性验证
5. 性能优化
- 数据采样
- 并行计算
- 增量式聚类
完整代码
完整的示例代码包括数据生成、聚类实现和结果可视化:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, AgglomerativeClustering
from sklearn.datasets import make_blobs
import seaborn as sns
from scipy.cluster.hierarchy import dendrogram, linkage
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 生成示例数据
def generate_data(n_samples=300):
"""生成示例数据"""
X, y = make_blobs(n_samples=n_samples, centers=4,
cluster_std=0.60, random_state=0)
return X
# K-means聚类
def kmeans_clustering(X, n_clusters=4):
"""执行K-means聚类"""
kmeans = KMeans(n_clusters=n_clusters, random_state=0)
y_kmeans = kmeans.fit_predict(X)
# 可视化结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
c='red', marker='x', s=200, linewidths=3, label='聚类中心')
plt.title('K-means聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.legend()
plt.savefig('cluster_analysis_13/images/kmeans_result.png')
plt.close()
# 层次聚类
def hierarchical_clustering(X, n_clusters=4):
"""执行层次聚类"""
# 使用层次聚类
clustering = AgglomerativeClustering(n_clusters=n_clusters)
y_hc = clustering.fit_predict(X)
# 可视化聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y_hc, cmap='viridis')
plt.title('层次聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.savefig('cluster_analysis_13/images/hierarchical_result.png')
plt.close()
# 绘制树状图
plt.figure(figsize=(10, 7))
linkage_matrix = linkage(X, method='ward')
dendrogram(linkage_matrix)
plt.title('层次聚类树状图')
plt.xlabel('样本索引')
plt.ylabel('距离')
plt.savefig('cluster_analysis_13/images/dendrogram.png')
plt.close()
# 评估不同K值的聚类效果
def evaluate_k_values(X, max_k=10):
"""评估不同K值的聚类效果"""
inertias = []
for k in range(1, max_k + 1):
kmeans = KMeans(n_clusters=k, random_state=0)
kmeans.fit(X)
inertias.append(kmeans.inertia_)
plt.figure(figsize=(10, 6))
plt.plot(range(1, max_k + 1), inertias, 'bo-')
plt.title('肘部法则图')
plt.xlabel('聚类数量 (k)')
plt.ylabel('聚类内平方和 (WCSS)')
plt.savefig('cluster_analysis_13/images/elbow_method.png')
plt.close()
if __name__ == "__main__":
# 生成数据
X = generate_data()
# 执行K-means聚类
kmeans_clustering(X)
# 执行层次聚类
hierarchical_clustering(X)
# 评估最佳K值
evaluate_k_values(X)
总结
本项目实现了两种常用的聚类算法:K-means聚类和层次聚类,并对其进行了可视化和评估。主要包含以下内容:
- 数据生成:使用make_blobs生成用于聚类分析的模拟数据
- K-means聚类:
- 实现基本的K-means聚类算法
- 可视化聚类结果
- 使用肘部法则评估最佳K值
- 层次聚类:
- 使用Ward方法进行层次聚类
- 可视化聚类结果
- 生成树状图展示聚类层次结构
- 评估方法:
- 使用轮廓系数评估聚类效果
- 通过肘部法则图选择最优聚类数量
通过本项目可以直观地理解和比较不同聚类算法的特点和适用场景。K-means适合球形簇,计算速度快;层次聚类则可以发现任意形状的簇,并提供聚类的层次结构信息。