系统聚类思想及其Python实现
系统聚类是一种将对象或数据按照其相似性进行分组的方法。与传统聚类方法不同,系统聚类通过构建一颗层次树(或称为树状图或谱系图)来展现数据的层次结构。在系统聚类中,数据点最初被视为单独的簇,然后通过逐步合并或分裂,形成一个层次结构的聚类结果。这种层次结构可用于分析数据的不同层次的相似性关系。系统聚类常用于生物学、分类学、社会网络等领域,其中对于数据之间的演化或关联关系的理解十分重要。系统聚类的结果可通过树状图直观地展示,为研究者提供了对数据结构和组织的更深层次的认识。在进行机器学习时,往往要把相似的样品点/数据点进行归类,相似度高的样品点会放在一起,这样一个样本就会被分成几类。而聚类分析也有很多种方法,比如分解法、加入法、有序样品的聚类、模糊聚类法以及系统聚类法等。这里学习系统聚类法,以及如何用python来进行系统聚类分析。
一、系统聚类的思想
系统聚类法(hierarchical clustering method),又叫分层聚类法,是目前最常用的聚类分析方法。其基本步骤如下:假设样本中有n个样品,那么就先将这n个样品看作n类,也就是一个样品一个类,然后将性质最接近的两类合并为一个新的类,这样就得到n-1个类,接着从中再找出最接近的两个类,让其进行合并,这样就变为n-2个类,让此过程持续进行下去,最后所有的样品都归为一类,把上述过程绘制成一张图,这个图就称为聚类图,从图中再决定分为多少类。其大致过程如下图所示。
1.1 样本间的距离
- 绝对值距离:
- 欧式距离:
- Minkowski距离:
- Chebyshev距离:
- 马氏距离: 其中:
1.2 类类间的距离
最短距离法(SINGLE):两类间距离的最小者
递推公式:
系统聚类方法的递推公式可以统一为:
方法 | ||||
---|---|---|---|---|
最短距离法(single linkage method) | 0 | |||
最长距离法(complete linkage method) | 0 | |||
中间距离法(median method) | 0 | |||
重心法(centroid hierarchical method) | 0 | |||
类平均法(Group average method) | 0 | 0 | ||
可变类平均 | 0 | |||
可变法 | 0 | |||
离差平方和(ward method) | 0 |
二、系统聚类算例
2.1 聚类计算过程展示
根据五个学生的六门课的成绩,对这五个学生进行分类。
ID | 数学 | 物理 | 化学 | 语文 | 历史 | 英语 |
---|---|---|---|---|---|---|
1 | 65 | 61 | 72 | 84 | 81 | 79 |
2 | 77 | 77 | 76 | 64 | 70 | 55 |
3 | 67 | 63 | 49 | 65 | 67 | 57 |
4 | 80 | 69 | 75 | 74 | 74 | 63 |
5 | 74 | 70 | 80 | 84 | 81 | 74 |
- 写出样本间的距离矩阵(以欧氏距离为例)
import numpy as np
from scipy.spatial.distance import pdist, squareform
# 给定的点集,每个点是一个包含6个数值的列表
points = np.array([
[65, 61, 72, 84, 81, 79], # A1
[77, 77, 76, 64, 70, 55], # A2
[67, 63, 49, 65, 67, 57], # A3
[80, 69, 75, 74, 74, 63], # A4
[74, 70, 80, 84, 81, 74] # A5
])
# 使用pdist计算所有点之间的距离
distances = pdist(points, 'euclidean') # 使用欧几里得距离
# 使用squareform将一维的距离数组转换为方阵形式
distance_matrix = squareform(distances)
# 打印距离矩阵,数值保留两位小数
print(np.round(distance_matrix, 1))
- 将每一个样本看做是一个类,即 。观察 最小,故将 与 聚为一类,记为 G6。计算新类与其余各类之间的距离,得到新的距离矩阵D1。
- 观察 最小,故将G2与G4聚为一类,记为 。计算新类与其余各类之间的距离,得到新的距离矩阵 D2。
- 观察 最小,故将G6与G7聚为一类,记为 。计算新类与其余各类之间的距离,得到新的距离矩阵 D3。
- 最后将 与 聚为一类, 记为 。
import numpy as np
from scipy.cluster.hierarchy import linkage, fcluster,dendrogram
from matplotlib import pyplot as plt
data = np.array([
[65, 61, 72, 84, 81, 79],
[77, 77, 76, 64, 70, 55],
[67, 63, 49, 65, 67, 57],
[80, 69, 75, 74, 74, 63],
[74, 70, 80, 84, 81, 74]
])
# 计算链接矩阵(linkage matrix)
Z = linkage(data, method='centroid')
f = fcluster(Z, t=25, criterion='distance')
# 绘制树状图(dendrogram)
fig = plt.figure(figsize=(10, 7))
dn = dendrogram(Z)
# 显示图形
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Sample index')
plt.ylabel('Distance')
plt.show()
# 打印链接矩阵Z,保留两位小数
print('Z:\n', np.round(Z, 2))
print('f:\n', f)
2.2 Python聚类函数详解
函数 | 作用 | 用法 | 参数 |
---|---|---|---|
linkage | linkage输出Z是包含聚类树信息的(n-1)×4矩阵(n表示样本数)。矩阵Z第1、2列表示被两两连接生成一个新类的对象索引;第3列表示两两对象的连接距离;第4列表示当前类中原始对象的个数。 | Z = linkage(X, method='centroid') | 第一个参数y为一个尺寸为(m,n)的二维矩阵。一共有n个样本,每个样本有m个维度。参数method =’single’:一范数距离;’complete’:无穷范数距离;’average’:平均距离;’centroid’:二范数距离;’ward’:离差平方和距离,返回值:(n-1)*4 的矩阵 Z |
fcluster | 这个函数压平(切割)树状图,根据距离阈值t——允许的最大簇间距离进行样本分配 | f =fcluster(Z, scalar, criterion)=fcluster(Z, t=3, criterion='distance') | 参数Z是linkage函数的输出Z;参数scalar:形成扁平簇的阈值t;参数criterion:’inconsistent’:预设的,如果一个集群节点及其所有后代的不一致值小于或等于t,那么它的所有叶子后代都属于同一个平面集群。’distance’:每个簇的距离不超过t;输出是每一个样本数据所在的类别。 |
dendrogram | 展示层次聚类产生的树状图,以便更直观地理解数据点之间的聚类结构。 | dendrogram(Z) | 参数Z是linkage函数的输出Z,这个矩阵是一个二维数组,其中每一行代表一次合并操作,包含了被合并的两个组群的索引以及它们之间的距离。 |
import numpy as np
from scipy.cluster.hierarchy import linkage, fcluster, dendrogram
from matplotlib import pyplot as plt
# 定义数据
X = np.array([[2], [8], [0], [4], [1], [9], [9], [0]])
# 计算链接矩阵
Z = linkage(X, method='centroid')
# 执行聚类
f = fcluster(Z, t=3, criterion='distance')
# 创建图形对象
fig = plt.figure(figsize=(5, 3))
# 绘制树状图
dn = dendrogram(Z)
# 打印链接矩阵Z,保留两位小数
print('Z:\n', np.round(Z, 2))
# 打印聚类结果f,保留两位小数(如果f中的数字需要格式化的话)
# 由于f是整数类型,通常不需要格式化小数位,但如果需要可以转换为浮点数并格式化
print('f:\n', f)
# 显示图形
plt.show()
程序中的链接矩阵看下表,表示矩阵的第行第列:
类别 | |||||
---|---|---|---|---|---|
0 | 2 | 7 | 0 | 2 | 8 |
1 | 5 | 6 | 0 | 2 | 9 |
2 | 0 | 4 | 1 | 2 | 10 |
3 | 8 | 10 | 1 | 4 | 11 |
4 | 1 | 9 | 1 | 3 | 12 |
5 | 3 | 11 | 2 | 5 | 13 |
6 | 12 | 13 | 4 | 8 | 14 |
表中行数据解析如下:
- 索引2和7对应 0 和 0,二者距离为 0,并且组成一个新的类,编号为8。
- 索引5和6对应 9 和 9,二者距离为 0,组成新类,编号为9。
- 索引0和4对应 2 和 3,二者距离为 1,组成新类,编号为10。
- 3和8对应 4 和 { 2:0,7:0 },类间距离为 2,组成新类,编号为11。
- ……以此类推
三、系统聚类案例的Python实现
import pandas as pd
from scipy.cluster.hierarchy import linkage, fcluster, dendrogram
import matplotlib.pyplot as plt
# 读取 country.csv 文件,见文中最后数据文件结构
X = pd.read_csv('country.csv', encoding='utf-8')
# 选择只包含数值型数据的列
numeric_cols = X.select_dtypes(include=['number']).columns
X_numeric = X[numeric_cols]
# 进行层次聚类
Z = linkage(X_numeric, method='ward') # 选择层次聚类的方法,这里使用Ward方法
#通过树状图可视化层次聚类结果
plt.figure(figsize=(15, 8))
dendrogram(Z)
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Sample Index')
plt.ylabel('Distance')
plt.show()
#根据树状图的切割高度,确定聚类簇的数量
cut_height = 300 # 根据实际情况调整
clusters = fcluster(Z, t=cut_height, criterion='distance')
#输出聚类结果
X['Cluster'] = clusters
print(X.head())
流程图 | 系统聚类图 |
---|---|
![]() |
![]() |
四、系统聚类练习案例
城市 | 乡村劳动力资源(人) | 农用机械总动力(千瓦) | 农村用电量(万千瓦小时) | 农村社会总产值(万元) | 自来受益村(个) | 通电村数(个) | 有效灌溉面积(公顷) | 农村运输业固定资产(万元) |
---|---|---|---|---|---|---|---|---|
石家庄 | 3849814 | 19001804 | 624877 | 37574543 | 3980 | 4418 | 495628 | 525146 |
唐山 | 3175708 | 9317581 | 1169791 | 48736085 | 3785 | 5020 | 499068 | 547760 |
秦皇岛 | 1201891 | 2782741 | 113192 | 6792279 | 847 | 2262 | 124364 | 138657 |
邯郸 | 3691615 | 12068651 | 448244 | 36969131 | 4590 | 5347 | 535707 | 435227 |
邢台 | 2992865 | 8278320 | 241519 | 21763646 | 4954 | 5172 | 553587 | 379118 |
保定 | 5446331 | 10247700 | 321625 | 28093014 | 4116 | 6210 | 655113 | 431368 |
张家口 | 1945917 | 2415071 | 68599 | 6484145 | 2863 | 4067 | 249021 | 159708 |
承德 | 1743264 | 2114710 | 121829 | 9254893 | 1620 | 2552 | 138738 | 182419 |
沧州 | 3212666 | 10811991 | 537227 | 34369166 | 5679 | 5741 | 561042 | 332882 |
廊坊 | 1706083 | 6467986 | 386814 | 23224066 | 3164 | 3222 | 283788 | 280718 |
衡水 | 1895102 | 7838729 | 267634 | 15258973 | 4933 | 4982 | 473719 | 138165 |
总结
系统聚类方法是一种将数据按照层次结构进行分组的聚类技术。其基本思想是通过构建一颗层次树,根据数据点之间的相似性逐步合并或分裂簇,形成层次化的聚类结果。系统聚类方法在生物学、分类学、社会网络分析等领域有广泛应用。在生物学中,系统聚类可用于分析物种的进化关系,揭示基因或蛋白质的功能相似性。在分类学中,它帮助研究者理解不同类别之间的关系。在社会网络分析中,系统聚类揭示了不同社群之间的联系,有助于理解网络结构和社会组织。系统聚类方法通过提供层次结构的视角,使得对数据的更深入理解成为可能,为各个领域的研究提供了有力工具。
参考文献
- 系统(层次)聚类原理详解及案例分析
- 层次聚类法应用实例及Python实现
- 原理+代码|详解层次聚类及Python实现
- 层次聚类python,scipy(dendrogram, linkage,fcluster函数)
用层次聚类法对世界20个国家和地区进行聚类,具体数据country.csv如下:
country | call | movecall | fee | computer | mips | net | |
---|---|---|---|---|---|---|---|
1 | 美 国 | 631.60 | 161.90 | 0.36 | 403.00 | 26073.00 | 35.34 |
2 | 日 本 | 498.40 | 143.20 | 3.57 | 176.00 | 10223.00 | 6.26 |
3 | 德 国 | 557.60 | 70.60 | 2.18 | 199.00 | 11571.00 | 9.48 |
4 | 瑞 典 | 684.10 | 281.80 | 1.40 | 286.00 | 16660.00 | 29.39 |
5 | 瑞 士 | 644.00 | 93.50 | 1.98 | 234.00 | 13621.00 | 22.68 |
6 | 丹 麦 | 620.30 | 248.60 | 2.56 | 296.00 | 17210.00 | 21.84 |
7 | 新加坡 | 498.40 | 147.50 | 2.50 | 284.00 | 13578.00 | 13.49 |
8 | 中国台湾 | 469.40 | 56.10 | 3.68 | 119.00 | 6911.00 | 1.72 |
9 | 韩 国 | 434.50 | 73.00 | 3.36 | 99.00 | 5795.00 | 1.68 |
10 | 巴 西 | 81.90 | 16.30 | 3.02 | 19.00 | 876.00 | 0.52 |
11 | 智 利 | 138.60 | 8.20 | 1.40 | 31.00 | 1411.00 | 1.28 |
12 | 墨西哥 | 92.20 | 9.80 | 2.61 | 31.00 | 1751.00 | 0.35 |
13 | 俄罗斯 | 174.90 | 5.00 | 5.12 | 24.00 | 1101.00 | 0.48 |
14 | 波 兰 | 169.00 | 6.50 | 3.68 | 40.00 | 1796.00 | 1.45 |
15 | 匈牙利 | 262.20 | 49.40 | 2.66 | 68.00 | 3067.00 | 3.09 |
16 | 马来西亚 | 195.50 | 88.40 | 4.19 | 53.00 | 2734.00 | 1.25 |
17 | 泰 国 | 78.60 | 27.80 | 4.95 | 22.00 | 1662.00 | 0.11 |
18 | 印 度 | 13.60 | 0.30 | 6.28 | 2.00 | 101.00 | 0.01 |
19 | 法 国 | 559.10 | 42.90 | 1.27 | 201.00 | 11702.00 | 4.76 |
20 | 英 国 | 521.10 | 122.50 | 0.98 | 248.00 | 14461.00 | 11.91 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!