层次聚类法应用实例及Python实现

一、层次聚类的概念

层次聚类算法(Hierarchical Clustering)将数据集划分为一层一层的簇(clusters),后面一层生成的簇是基于前面一层的结果。比较常用的方法是凝聚层次聚类(Agglomerative)简称AGNES算法。

1.AGNES聚类思路

1)最开始将每一个样本都视为一个簇,

2)每次按一定的准则将距离最近的两个簇合并生成一个新的簇

3)如此往复,直至最终所有的对象都属于一个簇。

例如:20国信息水平(见上一篇博客)聚类效果如下:

层次聚类是一种聚合算法

聚类的关键:在于定义簇间距离(当然也得知道样本间距离),进而不断合并簇

2.样本间距离与簇间距离

1) 样本间距离

x_i=(x_{1i},x_{2i},...x_{ni})^{T}为第i个样本对应的向量,x_j=(x_{1j},x_{2j},...x_{nj})^{T}为第j个样本对应的向量。则两个样本间距离定义如下:

(1)明氏距离

(2)马氏距离

其中,为两个向量构造出的协方差矩阵,

注意,仅当协方差矩阵可逆时,则马氏距离才存在。

(3)兰氏距离

.

此处仅适用于一切x_{ij}\geq 0的情况。

(3)夹角余弦

即表示两个样本i与j间距离。

(5)相关系数

.

即表示两个样本i与j间距离。

2)簇间距离

下面介绍几种簇间距离来度量簇与簇之间的差异。距离越大,说明簇与簇之间的差异越大。

簇间距离的定义要使用上述样本间距离(记作d_{ij}),下面介绍比较常用的四种。

1) 簇间最短距离

两个簇间最短距离为其中一个簇中所有成员到另一簇中的所有成员间距离的最小值。具体如下:

其中,c_p,c_q为两个不同的簇,d_{ij}为两个样本I与j之间的距离(上面定义的样本间距离).

2) 簇间最长距离

两个簇间最长距离为其中一个簇中所有成员到另一簇中的所有成员间距离的最大值。

3) 簇中心距离

设的c_p,c_q中心分别是\overline{x_p},\overline{x_q},则两个簇之间的距离定义为它们中心间样本距离:

4) 簇平均距离

一个簇的重心,虽然有很好的代表性,但未能充分利用各成员的信息,于是提出了利用两簇成员中两两之间的距离的平均值作为类与类之间的距离,即:

.

    *注:上述所有距离均可选用聚类中的数学指标中的样本相似度指标。

二、AGNES算法流程

步骤1:计算簇间距离度量 ,以及样本点间距离;

步骤2:令每个点为一个簇;

步骤3:计算任意两簇间的距离;

步骤4:合并距离最小的两个簇;

步骤5:重复步骤3-4,直到簇数达到预设的某个值k(或簇间距离达到某个阈值)为止。

三、AGNES算法的Python实现

方法1:用scipy.cluster.hierarchy的linkage函数实现簇的合并,并用dendrogram画聚类图,最后再使用fcluster函数决定最后聚类的结果(直到簇数达到预设的某个值k,或簇间距离达到某个阈值)

Z=scipy.cluster.hierarchy linkage(X, method='ward', metric='euclidean')

p = dendrogram(Z, 0)

labels =fcluster(Z, t=5, criterion='distance')

其中, method参数可以为:

’single’,’complete’,’average’,’centroid’,以及’ward’中的一种。分别对应:簇间最小距离、簇间最大距离、簇间平均距离、簇中心距离以及’ward’(使合并后的两个簇内样本点与合并后的中心点的对应方差最小的一种簇合并方式)等。metric为样本间距离度量,默认为’euclidean’. 即:欧几里得距离。

而fcluster的参数 criterion 取值为:'distance'(用阈值决定聚类),或'maxclust'(用最大簇数决定聚类),对应的临界距离或聚类的数量则由参数 t 所记录。fcluster 函数的结果labels为一个一维数组,记录每个样本的类别信息。

方法2:用sklearn.cluster.中的AgglomerativeClustering函数

Clustering=sklearn.cluster.AgglomerativeClustering(n_clusters=2, affinity=’euclidean’,linkage=’ward’).fit(X)   # X为待分类样本数据

labels = Clustering.fit_predict(data_M)   # labels即为聚类结果(分类标签)

其中,n_clusters为聚类的个数;

Affinity为样本间距离度量,默认为’euclidean’.

Linkage为簇间距离的方法,可选的值包括:“ward”, “complete”, “average”等。

例1用层次聚类法对sklearn.datas.make_blobs生成的数据聚类。

#方法1:使用用scipy实现聚类
#步骤1:生成数据
#程序如下:
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
centers = [[1, 1], [-1, -1], [1, -1]] #设置生成数据的样本中心
X, labels_true = make_blobs(n_samples=750, centers=centers, cluster_std=0.4, random_state=0)
plt.figure(figsize=(10, 8))
plt.scatter(X[:, 0], X[:, 1], c='b')
plt.show()
#步骤2:调用函数实现层次聚类
#SciPy 里面进行层次聚类,直接调用 linkage 函数。
#程序如下:
from scipy.cluster.hierarchy import linkage
Z = linkage(X, method='ward', metric='euclidean')
#print(Z.shape)
#print(Z[: 5])
#步骤3:画出树形图
#SciPy 中给出了根据层次聚类的结果 Z 绘制树形图的函数dendrogram
#程序如下:
from scipy.cluster.hierarchy import dendrogram
plt.figure(figsize=(10, 8))
dendrogram(Z,truncate_mode='lastp',p=20,show_leaf_counts=False, leaf_rotation=90, leaf_font_size=15,
show_contracted=True)
plt.show()
#步骤4:获取聚类结果
#② 是指定阈值d,得到在该距离以下的未合并的所有 cluster 作为聚类结果;
#② 是指定 cluster 的数量 k,函数会返回最后的 k 个 cluster 作为聚类结果。
#程序如下:
from scipy.cluster.hierarchy import fcluster
# 根据临界距离返回聚类结果
d = 15
labels_1 = fcluster(Z, t=d, criterion='distance')
print(labels_1[: 100]) # 打印聚类结果
print(len(set(labels_1))) # 看看在该临界距离下有几个 cluster
# 根据聚类数目返回聚类结果
k = 3
labels_2 = fcluster(Z, t=k, criterion='maxclust')
print(labels_2[: 100])
list(labels_1) == list(labels_2) # 看看两种不同维度下得到的聚类结果是否一致
# 聚类的结果可视化,相同的类的样本点用同一种颜色表示
plt.figure(figsize=(10, 8))
plt.scatter(X[:, 0], X[:, 1], c=labels_2, cmap='prism')
plt.show()

使用不同簇间距离效果

from time import time
import numpy as np
from sklearn.datasets import make_blobs
from scipy.cluster.hierarchy import linkage, fcluster
from sklearn.metrics.cluster import adjusted_mutual_info_score
import matplotlib.pyplot as plt
# 生成样本点
centers = [[1, 1], [-1, -1], [1, -1]]#设置生成数据的样本中心
X, labels = make_blobs(n_samples=750, centers=centers,
cluster_std=0.4, random_state=0)
# 可视化聚类结果
def plot_clustering(X, labels, title=None):
    plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='prism')
    if title is not None:
        plt.title(title, size=17)
        plt.axis('off')
        plt.tight_layout()
# 进行 Agglomerative 层次聚类
linkage_method_list = ['single', 'complete', 'average', 'ward']
plt.figure(figsize=(10, 8))
ncols, nrows = 2, int(np.ceil(len(linkage_method_list) / 2))
plt.subplots(nrows=nrows, ncols=ncols)
for i, linkage_method in enumerate(linkage_method_list):
    print('method %s:' % linkage_method)
    start_time = time()
    Z = linkage(X, method=linkage_method)
    labels_pred = fcluster(Z, t=3, criterion='maxclust')
    print('Adjust mutual information: %.3f' % adjusted_mutual_info_score(labels, labels_pred))
    print('time used: %.3f seconds' % (time() - start_time))
    plt.subplot(nrows, ncols, i + 1)
    plot_clustering(X, labels_pred, '%s linkage' % linkage_method)
plt.show()

除了用上面模块实现聚类,还可以使用使用sklearn.cluster的AgglomerativeClustering函数实现聚类,程序如下

from sklearn.datasets import make_blobs
from sklearn.cluster import AgglomerativeClustering
import matplotlib.pyplot as plt
# 生成样本点
centers = [[1, 1], [-1, -1], [1, -1]]
X, labels = make_blobs(n_samples=750, centers=centers,
cluster_std=0.4, random_state=0)
clustering = AgglomerativeClustering(n_clusters=3, linkage='ward').fit(X)
plt.figure(figsize=(10, 8))
plt.scatter(X[:, 0], X[:, 1], c=clustering.labels_, cmap='prism')
plt.show()

例2 用层次聚类法对世界20个国家和地区进行聚类,具体数据如下:

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

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
X= np.loadtxt("E:\\python教材\\信息基础设施数据.txt")#把信息水平数据存在本地位置
#计算簇间距离
from scipy.cluster.hierarchy import linkage
Z = linkage(X, method='ward', metric='euclidean')
#画层次结构图
from scipy.cluster.hierarchy import dendrogram
plt.figure(figsize=(10, 8))
dendrogram(Z,truncate_mode='lastp',p=20,show_leaf_counts=False, leaf_rotation=90, leaf_font_size=15,
show_contracted=True)
plt.show()
#使用两种方法聚类,并现实聚类结果
##方法1指定阈值d
from scipy.cluster.hierarchy import fcluster
# 根据临界距离返回聚类结果
d = 10000
labels_1 = fcluster(Z, t=d, criterion='distance')
print(labels_1[: 100]) # 打印聚类结果
print(len(set(labels_1))) # 看看在该临界距离下有几个 cluster
##方法2:根据聚类数目返回聚类结果
k = 3
labels_2 = fcluster(Z, t=k, criterion='maxclust')
print(labels_2[: 100])
list(labels_1) == list(labels_2) # 看看两种不同维度下得到的聚类结果是否一致

练习:请根据2007年河北省社会经济发展指标,对河北省11个市进行聚类分析。

数据选取2007年河北省社会经济发展指标因子8项,组成一个原始数据矩阵X,作为分析的依据。所选取的指标有:乡村劳动力资源(x1)、农用机械总动力(x2)、农村用电量(x3)、农村社会总产值(x4)、自来水受益村(x5)、通电话村(x6)、有效灌溉面积(x7)、农村运输业固定资产(x8)。具体数据如下:

城市

乡村劳动力资源(人)

农用机械

总动力

(千瓦)

农村用电量(万千瓦小时)

农村社会总产值

(万元)

自来受

益村

(个)

 通电村数

(个)

有效灌溉面积(公顷)

农村运输业固定资产(万元)

石家庄

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实现》陈星,吴松林

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
层次聚类算法是一种无监督学习算法,用于将相似的数据点分组成不同的聚类。它的应用非常广泛,例如在图像分割、文本聚类、生物信息学等领域都有应用。 以下是一个层次聚类算法应用实例: 假设我们有一组图书的目录数据,我们想要将相的图书进行聚类。我们可以使用层次聚类算法实现这个目。 首先,我们需要计算图书之间的相似度。可以使用一些相似度度量方,例如余弦相似度或欧氏距离。 然后,我们可以使用层次聚类算法来将相似的图书进行聚类层次聚类算法的主要思想是将每个数据点视为一个单独的聚类,然后逐步合并相似的聚类,直到达到预设的阈值。 具体的实现可以使用Java或Python等编程语言。在Java中,可以使用Weka等机器学习库来实现层次聚类算法。在Python中,可以使用scikit-learn等库来实现。 以下是一个使用Python实现层次聚类算法的示例代码: ```python from sklearn.cluster import AgglomerativeClustering import numpy as np # 假设我们有一组图书的特征向量数据 data = np.array([[1, 2], [2, 3], [3, 4], [8, 7], [9, 8], [10, 9]]) # 创建层次聚类模型 model = AgglomerativeClustering(n_clusters=2) # 进行聚类 clusters = model.fit_predict(data) # 输出每个数据点所属的聚类 print(clusters) ``` 这段代码将数据分为两个聚类,并输出每个数据点所属的聚类
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值