本文主要参考《Python机器学习经典实例》
在介绍凝聚层次聚类之前,我们需要先理解层次聚类(hierarchical clustering)。层次聚类是一组聚类算法,通过不断地分解或合并集群来构建树状集群(tree-like clusters)。层次聚类的结构可以用一颗树表示。层次聚类算法可以是自下而上的,也可以是自上而下的。具体是什么含义呢?在自下而上的算法中,每个数据点都被看作是一个单独的集群。这些集群不断地合并,直到所有的集群都合并成一个巨型集群。这被称为凝聚层次聚类。与之相反的是,自上而下层次的算法是从一个巨大的集群开始,不断地分解,直到所有的集群变成一个单独的数据点。
你可以在http://nlp.stanford.edu/IR-book/html/htmledition/hierarchical-agglomerative-clustering-1.html学习更多的内容。
详细步骤
(1) 首先建立agglomerative.py文件,然后导入一些需要用到的程序包:
import numpy as np
import matplotlib.pyplot as plt #用于画图工具
from sklearn.cluster import AgglomerativeClustering #层次聚类
from sklearn.neighbors import kneighbors_graph #最邻近搜索
临近搜索简单属性介绍
(2) 定义一个实现凝聚层次聚类的函数:
def perform_clustering(X, connectivity, title, num_clusters=3, linkage='ward'):
plt.figure()
# 定义凝聚层次聚类模型
model = AgglomerativeClustering(linkage=linkage,connectivity=connectivity, n_clusters=num_clusters)
model.fit(X) # 训练模型
(3) 提取标记,然后指定不同聚类在图形中的标记:
labels = model.labels_ # 提取标记
markers = '.vx' # 为每种集群设置不同的标记
(4) 迭代数据,用不同的标记把聚类的点画在图形中:
for i, marker in zip(range(num_clusters), markers):
# 画出属于某个集群中心的数据点
plt.scatter(X[labels==i, 0], X[labels==i, 1], s=50,marker=marker, color='k', facecolors='none')
plt.title(title)
注意:看到这里可能会有些有些疑问函数zip()是什么?如果有疑问可点击此链接有详细介绍pythonzip()函数。
如果对plt.scatter()有迟疑的话此处有详细介绍点击打开链,由于篇幅问题这里就不详细解释。
(5) 为了演示凝聚层次聚类的优势,我们用它对一些在空间中是连接在一起、但彼此却非常
接近的数据进行聚类。我们希望连接在一起的数据可以聚成一类,而不是在空间上非常接近的点
聚成一类。下面定义一个函数来获取一组呈螺旋状的数据点:
# 定义函数获取螺旋状的数据点
def get_spiral(t, noise_amplitude=0.5):
r = t
x = r * np.cos(t)
y = r * np.sin(t)
return add_noise(x, y, noise_amplitude)
(6) 在上面的函数中,我们增加了一些噪声,因为这样做可以增加一些不确定性。下面定义
噪声函数:
def add_noise(x, y, amplitude):
X = np.concatenate((x, y))
X += amplitude * np.random.randn(2, X.shape[1])
return X.T
(7) 我们再定义一个函数来获取位于玫瑰曲线上的数据点(rose curve,又称为rhodonea curve,
极坐标中的正弦曲线):
def get_rose(t, noise_amplitude=0.02):
# 设置玫瑰曲线方程;如果变量k是奇数,那么曲线有k朵花瓣;如果k是偶数,那么有2k朵花瓣
k = 5
r = np.cos(k*t) + 0.25
x = r * np.cos(t)
y = r * np.sin(t)
return add_noise(x, y, noise_amplitude)
(8) 为了增加多样性,我们再定义一个hypotrochoid函数:
def get_hypotrochoid(t, noise_amplitude=0):
a, b, h = 10.0, 2.0, 4.0
x = (a - b) * np.cos(t) + h * np.cos((a - b) / b * t)
y = (a - b) * np.sin(t) - h * np.sin((a - b) / b * t)
return add_noise(x, y, 0)
(9) 现在可以定义主函数main了:
if __name__=='__main__':
# 生成样本数据
n_samples = 500
np.random.seed(2)
t = 2.5 * np.pi * (1 + 2 * np.random.rand(1, n_samples))
X = get_spiral(t)
# 不考虑螺旋形的数据连接性
connectivity = None
perform_clustering(X, connectivity, 'No connectivity')
# 根据数据连接线创建K个临近点的图形
connectivity = kneighbors_graph(X, 10, include_self=False)
perform_clustering(X, connectivity, 'K-Neighbors connectivity')
plt.show()
注意:如果你看到 __name__=='__main__'不懂得话可以点开此处点击打开链接
(10) 运行代码,可以看到如图1所示的图形(没有用任何连接特征)。
图1