"> "> 机器学习-聚类 | Yufei Luo's Blog

机器学习-聚类

概述

聚类(Clustering)算法是一种无监督学习算法,它试图将数据集中的样本划分为若干个不相交的子集,每一个子集被称为一个“簇(Cluster,或被称为类)”。通过这样的划分,每个簇可能对应于一些潜在的概念,但是这些概念对于聚类算法而言事先是未知的,聚类过程仅仅能够自动形成簇结构,这些簇所对应的概念需要通过人工来把握。

使用数学语言,聚类算法可以描述为如下的形式:假设样本集\(D=\{\boldsymbol{x}_1,\boldsymbol{x}_2,\dots,\boldsymbol{x}_m\}\)包含\(m\)个无标记样本,每个样本\(\boldsymbol{x}_i=\{x_{i1},x_{i2},\dots,x_{in}\}\)是一个\(n\)维的特征向量。聚类算法将样本集\(D\)划分为\(k\)个(\(k\)的值为手动设定)不相交的簇\(\{C_l|l=1,2,\dots,k\}\),其中\(C_{l'}\cap_{l'\ne l}C_l=\empty\)\(D=\cup_{l=1}^{k}C_l\)。如果我们用\(\lambda_j\in \{1,2,\dots,k\}\)表示样本\(\boldsymbol{x}_j\)的“簇标记”(即\(\boldsymbol{x}_j \in C_{\lambda_j}\)),则聚类结果可以使用包含\(m\)个元素的簇标记向量\(\boldsymbol{\lambda}=(\lambda_1,\lambda_2,\dots,\lambda_m)\)表示。聚类算法具有多种不同类型,它们的区别在于将样本划分到不同的簇时所使用的策略不同。

聚类既可以作为一个单独过程,用于找寻数据内在的分布结构,也可以作为分类等其他学习任务的前驱过程。例如在商业应用中需要对新用户的类型进行判别,但是定义“用户类型”对商家来说可能不太容易。此时可以先使用已有的用户数据进行聚类,根据聚类结果为每个簇定义一个类,然后基于这些类训练分类模型,用于判断新用户的类型。

距离计算

在聚类算法中,如何计算样本\(i,j\)之间的距离\(d_{ij}\)是一个核心问题,它直接影响了聚类的结果。常用的距离度量方式包括:

  • 闵可夫斯基距离(闵氏距离): \[ d_{ij}=\left(\sum_{u=1}^n|x_{iu}-x_{ju}|^p\right)^{\frac{1}{p}},p\ge 1 \]

    • \(p=1\)时被称为曼哈顿距离\(d_{ij}=\left(\sum_{u=1}^n|x_{iu}-x_{ju}|\right)\)
    • \(p=2\)时被称为欧氏距离\(d_{ij}=\left(\sum_{u=1}^n|x_{iu}-x_{ju}|^2\right)^{\frac{1}{2}}\)
    • \(p=\infty\)时被称为切比雪夫距离\(d_{ij}=\max_{u}|x_{iu}-x_{ju}|\)

    需要注意的是,如果特征\(u\)为一个有序属性(连续值,或者有序的离散数值),计算距离的时候便可以直接取其值进行计算;但是如果为无序属性(无序的离散数值、或者类别型变量),则需要使用VDM(Value Difference Metric)来计算。假设\(x_{iu}\)的值为\(a\)\(x_{ju}\)的值为\(b\),那么VDM的计算公式可以写成如下形式: \[ |x_{iu}-x_{ju}|^p=\sum_{c=1}^{k}\left| \frac{m_{u,a,c}}{m_{u,a}}-\frac{m_{u,b,c}}{m_{u,b}} \right|^p \] 其中,\(m_{u,a,c}\)指的是在第\(c\)个簇中,属性\(u\)上取值为\(a\)的样本数;\(m_{u,a}\)指的是属性\(u\)上取值为\(a\)的样本数;\(m_{u,b,c}\)指的是在第\(c\)个簇中,属性\(u\)上取值为\(b\)的样本数;\(m_{u,b}\)指的是属性\(u\)上取值为\(b\)的样本数。

    如果样本空间中不同属性的重要性不同,可以使用如下的加权闵可夫斯基距离: \[ d_{ij}=\left(\sum_{u=1}^nw_u|x_{iu}-x_{ju}|^p\right)^{\frac{1}{p}},p\ge 1,\sum_{u=1}^{n}w_u=1 \]

    注意:在使用闵氏距离时,每个特征的取值范围最好接近甚至完全相同(可以通过正则化、归一化等手段进行转化)。否则在计算距离时,如果某个特征的数值过大便会对距离的计算结果影响很大,而如果某个特征的数值过小则对距离几乎没有影响。当然从另一个角度考虑,也可以把不同特征的数值范围当成是一种特殊的权重。

  • 马哈拉诺比斯距离(马氏距离): \[ d_{ij}=\left[ (\boldsymbol{x}_i-\boldsymbol{x}_j)S^{-1}(\boldsymbol{x}_i-\boldsymbol{x}_j)^T \right]^{\frac{1}{2}} \] 其中\(S\)代表样本矩阵\(X=\begin{bmatrix}\boldsymbol{x}_1 \\ \boldsymbol{x}_2 \\ \vdots \\ \boldsymbol{x}_m \end{bmatrix}\)的协方差矩阵。

    马氏距离越大,则两个样本之间的相似度越小,反之则相似度越大。

  • 相关系数: \[ r_{ij}=\frac{\sum_{k=1}^{n}(x_{ik}-\bar{x}_i)(x_{jk}-\bar{x}_j)}{\left[ \sum_{k=1}^{n}(x_{ik}-\bar{x}_i)^2\sum_{k=1}^{n}(x_{jk}-\bar{x}_j)^2 \right]^{\frac{1}{2}}} \] 其中\(\bar{x}_i=\frac{1}{n}\sum_{k=1}^{n}x_{ik}\)\(\bar{x}_j=\frac{1}{n}\sum_{k=1}^{n}x_{jk}\)

    相关系数的绝对值越接近于1代表样本越相似,越接近于0则代表样本越不相似。

  • 夹角余弦: \[ s_{ij}=\frac{\sum_{k=1}^n x_{ik}x_{jk}}{[\sum_{k=1}^n x_{ik}^2\sum_{k=1}^n x_{jk}^2]^{\frac{1}{2}}} \] 夹角余弦的绝对值值越接近于1,代表两个样本越相似,越接近于0则代表越不相似。

需要注意的是,使用不同的度量标准所得到的结果可能并不一致,需要根据实际问题的特点进行合理选择。

K均值聚类

算法原理

给定样本集\(D=\{\boldsymbol{x}_1,\boldsymbol{x}_2,\dots,\boldsymbol{x}_m\}\),K均值(\(k\)-means)聚类算法针对于聚类所得到的簇划分\(\mathcal{C}=\{C_1,C_2,\dots,C_k\}\),最小化如下的平方误差表达式: \[ E=\sum_{i=1}^{k}\sum_{\boldsymbol{x}\in C_i}||\boldsymbol{x}-\boldsymbol{\mu}_i||_2^2 \] 其中\(\boldsymbol{\mu}_i=\frac{1}{|C_i|}\sum_{\boldsymbol{x}\in C_i}\boldsymbol{x}\)代表了簇\(C_i\)的均值向量。

从定性角度去分析,上述的平方误差表达式刻画了簇内样本围绕簇均值向量的紧密程度,\(E\)的值越小也就意味着簇内样本的相似度越高。

如果要找到其全局最优解,则需要分析样本集\(D\)所有可能的簇划分,因此求解这一平方误差表达式是一个NP难问题。故实际中通常使用如下的贪心算法去求一个近似解:

  1. 从样本集\(D\)中随机选取\(k\)个样本,作为\(k\)个簇的初始均值向量\(\{\boldsymbol{\mu}_1,\boldsymbol{\mu}_2,\dots,\boldsymbol{\mu}_k\}\)
  2. 计算每个样本\(\boldsymbol{x}_j\)与各个均值向量\(\boldsymbol{\mu}_i\)之间的距离\(d_{ij}=||\boldsymbol{x}_j-\boldsymbol{\mu}_i||_2\),然后更新样本\(\boldsymbol{x}_j\)的簇标记为\(\lambda_j=\text{arg}\min_{i\in\{1,2,\dots,k\}}d_{ij}\)(即选择与该样本最近的那个均值向量所对应的簇)
  3. 为每个簇更新均值向量\(\boldsymbol{\mu}_i'=\frac{1}{|C_i|}\sum_{\boldsymbol{x}\in C_i}\boldsymbol{x}\)
  4. 重复2和3,直到所有的均值向量都没有被更新

下图所示为K均值聚类的迭代过程:

k均值聚类

讨论

对比高斯混合模型

K均值聚类可以看作是高斯混合模型的一种特殊情况。首先,我们分析当高斯分布中的\(\sigma\)变化时,会对高斯混合模型有什么影响。

image-20210308225628217

在上图中,左边代表\(\sigma\)取不同值时,两个\(\mu\)值不同的高斯分布\(g_0(x)\)\(g_1(x)\)所对应的概率密度分布图;右边代表两模型相对密度\(\frac{g_0(x)}{g_0(x)+g_1(x)}\)\(\frac{g_1(x)}{g_0(x)+g_1(x)}\)随着变量\(x\)的变化趋势。

从中可以看出,当\(\sigma\)的值较大时,两个高斯模型会为图中绿色虚线处所对应的数据点赋予一个较“软”的分类准则,即这个数据点属于这两个高斯模型的概率差别不大,两个模型所对应的\(E(\gamma_{jk})\)的值也相差不大(此处可以回顾EM算法和高斯混合模型的相关内容);而当\(\sigma\)的值减小时,这个分类准则会逐渐变“硬”,即两个模型所对应的\(E(\gamma_{jk})\)的值也会相差的越来越大,最终结果倾向于该数据点来自于其中的某一个高斯模型。

我们考虑最极端的情况,即\(\sigma=0\)的情形,此时高斯分布会变为\(\delta\)分布(狄拉克\(\delta\)函数),而此时的高斯混合模型也会变为K均值聚类。因为此时在计算\(E(\gamma_{jk})\)的时候,它的值要么为1要么为0,从而导致计算\(\mu\)的时候变成了聚类的计算方式。

K值的选择

在实际使用聚类算法时,选择合适的K值对于最终得到的结果有很大影响。如果选择的K值过小,则每个簇中的数据点过于分散;而K值过大时,虽然每个簇中的数据点会相对集中,但是也会因此而出现一些比较相似的簇(两个簇中心之间的距离很小)。因此需要选择一个合适的K值。常用确定K的方法有下面两种:

  1. 手肘法(Elbow method)

    手肘法以如下的误差平方和(Sum of the Squared Errors)作为核心指标: \[ E=\sum_{i=1}^{k}\sum_{\boldsymbol{x}\in C_i}||\boldsymbol{x}-\boldsymbol{\mu}_i||_2^2 \] 这一方法的思想是,随着聚类数K的增大,样本的划分会更加精细,每个簇的聚合程度会逐渐提高,从而导致误差平方和的值逐渐变小。当K小于真实聚类数时,随着K的增大误差平方和的值会快速下降;而当K到达真实聚类数之后,再增加K时,每个簇内聚合程度的增加便没有那么明显,也就是说误差平方和的下降幅度会骤减。

    因此总的来看,误差平方和与K的关系图会形成一个形似手肘的形状,而这个“肘部”对应的K值便是最合适的聚类数(理论上更接近数据的真实聚类数)。如下图所示:

    手肘法
  2. 轮廓系数法

    轮廓系数法以的轮廓系数(Silhouette Coefficient)作为核心指标。某个样本点\(\boldsymbol{x}_j\in C_i\)的轮廓系数按照如下公式进行计算: \[ S=\frac{b-a}{\max(a,b)} \] 其中,\(a\)代表\(\boldsymbol{x}_j\)与同簇其它样本的平均距离,即\(a=\frac{1}{|C_i-1|}\sum_{\boldsymbol{x}\in C_i}||\boldsymbol{x}-\boldsymbol{x}_j||_2\),称为凝聚度;\(b\)代表\(\boldsymbol{x}_j\)与除自身所在簇之外的最近簇中所有样本的平均距离,即\(b=\min_{C_k}(\frac{1}{|C_k|}\sum_{\boldsymbol{x}\in C_k}||\boldsymbol{x}-\boldsymbol{x}_j||_2),k\ne i\),称为分离度。

    求出所有样本的轮廓系数之后再计算平均值即可得到平均轮廓系数。轮廓系数的值在\([-1,1]\)之间,数值越大代表聚类效果越好,反之则说明聚类效果越差。

代码示例

我们使用Sklearn自带的make_blobs函数来人工生成数据,来演示如何使用sklearn中的K-Means聚类。给定簇的数量以及每个簇内的元素个数,make_blobs函数会按照多元高斯分布为每一个簇生成数据。其中每个簇的中心可以自己定义,也可以随机生成;每个簇的标准差也可以自己定义或者是全部使用相同的标准差。

我们使用随机生成的簇中心以及标准差来生成6个簇,然后对这些簇使用K-Means。

1
2
3
4
5
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib
from sklearn.datasets import make_blobs
1
2
3
4
5
6
x,y=make_blobs(
n_samples=[100,180,200,150,120,80],
n_features=2,
centers=(np.random.rand(6,2)-0.5)*20,
cluster_std=(np.random.rand(6,1)+1)
)
1
from sklearn.cluster import KMeans

KMeans类在初始化时的关键参数有:

  • n_clusters:代表将数据聚集为多少个簇,默认值为8
  • init:初始化方式,默认使用'k-means++',也可以使用'random';或是传入一个list;还可以传入一个函数,这个函数以数据集和簇个数为输入,输出为初始化的簇中心
  • n_init:生成多少组初始簇,最终结果从这些结果中选取最佳值。默认为10

首先我们使用手肘法,找出最优的簇数目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def elbow_method(x,max_clusters=12):
clusters=[]
inertias=[]
for i in range(max_clusters):
kmeans=KMeans(n_clusters=i+1,n_init=50)
kmeans.fit_predict(x)
clusters.append(i+1)
inertias.append(kmeans.inertia_/x.shape[0])

fig=plt.figure(figsize=(5,4))
axes=fig.subplots(1,1)
axes.plot(clusters,inertias)
axes.set_xlabel('Number of Clusters')
axes.set_ylabel('Mean Squared Distance from Nearest Center')
1
elbow_method(x)
手肘法-代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
colorlists=['tab:gray','tab:purple','tab:blue','tab:green','tab:orange','tab:red']
colormaps=['Greys','Purples','Blues','Greens','Oranges','Reds']

def plot_kmeans(model,fig,axes,x,clusters):
X_mesh,Y_mesh=np.meshgrid(np.linspace(-15,15,1000),np.linspace(-15,15,1000))
XY_mesh=np.concatenate([X_mesh.reshape(-1,1),Y_mesh.reshape(-1,1)],axis=1)

mu=model.cluster_centers_
mesh_pred=model.predict(XY_mesh)
y_pred=model.predict(x)

for i in range(clusters):
axes.contourf(X_mesh,Y_mesh,mesh_pred.reshape(X_mesh.shape),cmap='Pastel1')
for i in range(clusters):
axes.scatter(x[y_pred==i,0],x[y_pred==i,1],c=colorlists[i])

axes.plot(mu[:,0],mu[:,1],c='black',marker='*',markersize=15,linewidth=0)

axes.set_xlim(-12,12)
axes.set_ylim(-12,12)
1
2
3
4
5
6
kmeans=KMeans(n_clusters=4,n_init=50)
kmeans.fit(x)

fig=plt.figure(figsize=(8,6))
axes=fig.subplots(1,1)
plot_kmeans(kmeans,fig,axes,x,4)
K-Means结果

DBSCAN

概述

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种著名的密度聚类算法,这类算法假设聚类结构能够通过样本分布的紧密程度确定。通常情况下,密度聚类算法从样本密度的角度来考察样本之间的可连接性,并基于可连接样本不断扩展聚类簇从而获得最终的聚类结果。

为了介绍DBSCAN算法,首先我们在给定数据集\(D=\{\boldsymbol{x}_1,\boldsymbol{x}_2,\dots,\boldsymbol{x}_m\}\)的条件下,引入如下的几个概念:

  • \(\epsilon\)-邻域:对\(\boldsymbol{x}_j\in D\),其\(\epsilon\)-邻域包含样本集\(D\)中与\(\boldsymbol{x}_j\)的距离不大于\(\epsilon\)的样本,即\(N_{\epsilon}(\boldsymbol{x}_j)=\{\boldsymbol{x}_i\in D|\text{dist}(\boldsymbol{x}_i,\boldsymbol{x}_j)\le \epsilon \}\)
  • 核心对象:如果\(\boldsymbol{x}_j\)\(\epsilon\)-邻域至少包含\(MinPts\)个样本,即\(|N_{\epsilon}(\boldsymbol{x}_j)|\ge MinPts\),则\(\boldsymbol{x}_j\)是一个核心对象(也被称为核心点)
  • 密度直达:如果\(\boldsymbol{x}_j\)位于\(\boldsymbol{x}_i\)\(\epsilon\)-邻域,且\(\boldsymbol{x}_i\)为核心对象,则称\(\boldsymbol{x}_j\)\(\boldsymbol{x}_i\)密度直达
  • 密度可达:对于\(\boldsymbol{x}_i\)\(\boldsymbol{x}_j\),如果存在一组样本序列\(\boldsymbol{p}_1,\boldsymbol{p}_2,\dots,\boldsymbol{p}_n\),其中\(\boldsymbol{p}_1=\boldsymbol{x}_i,\boldsymbol{p}_n=\boldsymbol{x}_j\),且\(\boldsymbol{p}_{i+1}\)\(\boldsymbol{p}_i\)密度直达,则称\(\boldsymbol{x}_j\)\(\boldsymbol{x}_i\)密度可达
  • 密度相连:对于\(\boldsymbol{x}_i\)\(\boldsymbol{x}_j\),如果存在\(\boldsymbol{x}_k\)使得\(\boldsymbol{x}_i\)\(\boldsymbol{x}_j\)均由\(\boldsymbol{x}_k\)密度可达,则称\(\boldsymbol{x}_i\)\(\boldsymbol{x}_j\)密度相连

基于上述这些概念,DBSCAN将簇定义为:由密度可达关系导出的最大密度相连样本集合。用数学语言可以描述为,给定邻域参数\((\epsilon,MinPts)\),簇\(C\subseteq D\)是满足连接性与最大性的非空样本子集。其中,连接性指的是对于\(\boldsymbol{x}_i,\boldsymbol{x}_j\in C\)\(\boldsymbol{x}_i,\boldsymbol{x}_j\)之间密度相连;最大性指的是如果\(\boldsymbol{x}_i\in C\),同时\(\boldsymbol{x}_j\)\(\boldsymbol{x}_i\)密度可达,那么\(\boldsymbol{x}_j\in C\)

需要注意的是,使用DBSCAN算法时,最终会有一些点不属于任何的簇,这些簇被定义为噪音点或者离群点。

算法步骤

DBSCAN在生成聚类簇时的主要操作步骤如下:

  1. 根据给定的邻域参数\((\epsilon,MinPts)\),找到所有的核心对象
  2. 任意选择一个核心对象作为出发点,寻找所有与其密度可达的点组成聚类簇
  3. 重复第2步,直到所有的核心对象均被访问过为止

下图为DBSCAN生成聚类簇的过程:

DBSCAN步骤

优缺点分析

优点

  • 不需要事先设定簇的数目

  • 可以发现任意形状的簇,正如下图所示的DBSCAN聚类的结果图

    img

  • 能够找出数据中的噪音,且对噪音不敏感

  • 聚类结果几乎不依赖于结点的遍历顺序

缺点

  • 聚类质量依赖于距离公式的选取,对于高维数据而言,可能存在维度灾难的问题
  • 算法不适用于数据集内密度差异或很大的情形,因为此时很难确定模型的参数

代码示例

我们同样使用Sklearn自带的make_blobs函数来人工生成数据,来演示如何使用sklearn中的DBSCAN算法。使用随机生成的簇中心以及标准差来生成6个簇,然后对这些簇使用DBSCAN。

1
2
3
4
5
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib
from sklearn.datasets import make_blobs
1
2
3
4
5
6
x,y=make_blobs(
n_samples=[100,180,200,150,120,80],
n_features=2,
centers=(np.random.rand(6,2)-0.5)*20,
cluster_std=(np.random.rand(6,1)+1)
)
1
sns.scatterplot(x[:,0],x[:,1])
DBSCAN-1

DBSCAN类在初始化时的关键参数有:

  • eps:两点被当成相邻的最小距离,它是DBSCAN中的重要参数。默认为0.5
  • min_samples:中心点的周围至少要有多少个点与它相邻
  • metric:距离计算方式,默认为'euclidean',也可以传入一个函数
1
from sklearn.cluster import DBSCAN
1
dbscan=DBSCAN(eps=0.2)
1
y_pred=dbscan.fit_predict(x)

我们将DBSCAN找出的中心点、密度相连点和离群点使用不同的颜色标记出来,可以得到下图。可以看到,DBSCAN的结果与我们选择的\(\epsilon\)值有很大关系。

1
2
3
4
5
6
7
8
9
10
11
def plot_dbscan(fig,axes,x,epsilon):
dbscan_model=DBSCAN(eps=epsilon)
y_pred=dbscan_model.fit_predict(x)
max_val=np.max(y_pred)
for i in range(max_val+1):
axes.scatter(x[y_pred==i,0],x[y_pred==i,1],c='tab:olive')

axes.scatter(x[dbscan_model.core_sample_indices_,0],x[dbscan_model.core_sample_indices_,1],c='tab:green',marker='*')
axes.scatter(x[y_pred==-1,0],x[y_pred==-1,1],c='tab:red',s=7)
axes.set_xlim(-12,12)
axes.set_ylim(-12,12)
1
2
3
4
5
fig=plt.figure(figsize=(24,6))
axes=fig.subplots(1,3)
plot_dbscan(fig,axes[0],x,0.2)
plot_dbscan(fig,axes[1],x,0.5)
plot_dbscan(fig,axes[2],x,1.0)
DBSCAN-2

层次聚类

算法原理

层次聚类试图在不同的层次上对数据集进行划分,从而形成树形的聚类结构。数据集的划分可采取自底向上的聚合策略,也可采取自顶向下的分拆策略。

AGNES是一种采用自底向上聚合策略的层次聚类算法,它先将数据集中的每一个样本当成一个初始聚类簇,然后在算法运行的每一步中找出距离最近的两个聚类簇进行合并。重复以上过程,直至达到预设的聚类簇个数。最终会形成一个类似于树状图一样的结果。

实际上,每个簇是一个样本集合。给定聚类簇\(C_i\)\(C_j\),可以通过下面的方法来衡量两个簇之间的距离:

  • 最小距离:\(d_{\min}(C_i,C_j)=\min_{\boldsymbol{x}\in C_i,\boldsymbol{z}\in C_j} \text{dist}(\boldsymbol{x},\boldsymbol{z})\)
  • 最大距离:\(d_{\max}(C_i,C_j)=\max_{\boldsymbol{x}\in C_i,\boldsymbol{z}\in C_j} \text{dist}(\boldsymbol{x},\boldsymbol{z})\)
  • 平均距离:\(d_{\text{avg}}(C_i,C_j)=\frac{1}{|C_i||C_j|}\sum_{\boldsymbol{x}\in C_i} \sum_{\boldsymbol{z}\in C_j} \text{dist}(\boldsymbol{x},\boldsymbol{z})\)

当聚类簇距离分别由\(d_{\min},d_{\max},d_{\text{avg}}\)计算时,AGNES算法被相应地称为“单链接”(Single-linkage)、“全链接”(Complete-linkage)或“均链接”(Average-linkage)算法。下图所示便为同一数据集使用这三种不同的计算公式所得到的层次聚类结果:

image-20210310221448018

在层次聚类树状图的特定层次上进行分割,可以得到相应的簇划分结果。如下图所示便为不同层次上分割时所得到的不同聚类结果:

image-20210310221955331

代码示例

同样地,我们使用Sklearn自带的make_blobs函数来人工生成数据,来演示如何在sklearn中使用层次聚类。

AgglomerativeClustering类在初始化时的关键参数有:

  • n_clusters:最终得到多少个簇,默认值为2
  • affinity:计算簇之间连接性的指标,可以使用"euclidean"(默认), "l1", "l2", "manhattan", "cosine"或"precomputed".
  • linkage:簇之间连接性的计算方式,可以使用"ward"(默认), "complete", "average", "single"。ward选择合并后方差最小的两个簇进行合并,后面三个分别代表取两簇中样本距离的最大值、平均值、最小值作为判断标准。
1
from sklearn.cluster import AgglomerativeClustering
1
2
3
4
5
6
7
8
def plot_agg_cluster(fig,axes,x,clusters,linkage_type):
agg_cluster_model=AgglomerativeClustering(n_clusters=clusters,linkage=linkage_type)
y_pred=agg_cluster_model.fit_predict(x)
for i in range(clusters):
axes.scatter(x[y_pred==i,0],x[y_pred==i,1])
axes.set_xlim(-12,12)
axes.set_ylim(-12,12)
axes.set_title('linkage={}'.format(linkage_type))
1
2
3
4
5
linkages=["ward","complete","average","single"]
fig=plt.figure(figsize=(30,5))
axes=fig.subplots(1,4)
for i in range(4):
plot_agg_cluster(fig,axes[i],x,4,linkages[i])
层次聚类-代码示例

参考

  1. 机器学习,周志华
  2. The Elements of Statistical Learning
  3. https://blog.csdn.net/sxllllwd/article/details/82151996
  4. https://blog.csdn.net/zhouxianen1987/article/details/68945844
  5. https://blog.csdn.net/itplus/article/details/10088625