层次聚类算法的工作流程如下。首先,每个点自己单独看成一个簇。随着时间的推移,算法会通过合并两个小簇而形成一个大簇。
首先,我们假定算法运行在欧式空间下。此时可以允许通过簇质心或者簇内平均点来表示一个簇。注意到对于单点组成的簇,该点就是簇质心,因此可以很直观地对这些簇进行初始化。然后我们将簇之间距离定义为其质心之间的欧氏距离,并选择具有最短距离的两个簇进行合并。
簇之间的距离有很多种定义:
1簇的半径
2簇的直径
3两个簇中点对之间距离的平均值
4 两个簇中所有点之间的最短距离
利用函数scipy.cluster.hierarchy,我们可以轻松实现分层聚类
# -*- coding: utf-8 -*-
import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage, fcluster
from matplotlib import pyplot as plt
def hierarchy_cluster(data, method='average', threshold=5.0):
data = np.array(data)
#使用非加权组平均法,计算簇与簇之间的距离,然后形成层次树
Z = linkage(data, method=method)
#根据linkage的结果进行聚类
cluster_assignments = fcluster(Z, threshold, criterion='distance')
print(cluster_assignments)
num_clusters = cluster_assignments.max()
indices = get_cluster_indices(cluster_assignments)
fig = plt.figure(figsize=(5, 3))
dn = dendrogram(Z)
plt.show()
return num_clusters, indices
def get_cluster_indices(cluster_assignments):
'''映射每一类至原数据索引
Arguments:
cluster_assignments 层次聚类后的结果
Returns:
[[idx1, idx2,..], [idx3]] -- 每一类下的索引
'''
#有多少种聚类簇
n = cluster_assignments.max()
indices = []
for cluster_number in range(1, n + 1):
indices.append(np.where(cluster_assignments == cluster_number)[0])
return indices
if __name__ == '__main__':
arr = [[0., 21.6,2],
[21.6, 0.,2],
[22.6, 1.,2],
[63.9, 42.3,2],
[65.1, 43.5,2],
[17.7, 3.9,2],
[99.2, 77.6,2],
[100,118,2],
[101,119,2],
[98,118,2],
[54,63,2],
[55,63,2],
[55,64,2]
]
arr = np.array(arr)
r, c = arr.shape
num_clusters, indices = hierarchy_cluster(arr)
print ('%d clusters' % num_clusters)
for k, ind in enumerate(indices):
print ('cluster', k, 'is', ind)
程序效果图:
参考图书:大数据互联网大规模数据挖掘与分布式处理(第2版)