机器学习 — python(sklearn / scipy) 实现层次聚类,precomputed自定义距离矩阵

news/2024/5/20 10:15:51 标签: 聚类, python, 机器学习

文章目录

  • 机器学习python(sklearn / scipy) 实现层次聚类,precomputed自定义距离矩阵
    • 一. scipy实现
      • (一) 函数说明
        • 1. linkage
        • 2. fcluster
      • (二) 示例含完整算法
    • 二、sklearn实现
      • (一) 函数说明
      • (二) 完整算法
        • 补充基于预计算(precomputed)的距离矩阵的算法
    • 参考资料

pythonsklearn__scipy_precomputed_1">机器学习python(sklearn / scipy) 实现层次聚类,precomputed自定义距离矩阵

关于层次聚类的原理,可以参考我的另一篇博客:层次聚类原理。本博客主要讲解如何简单直接使用 python 来实现层次聚类

本篇博客包含的内容:sklearn / scipy 两种方式实现层次聚类,以及在 sklearn 中通过 precomputed 参数实现自定义距离矩阵

一. scipy实现

(一) 函数说明

主要是两个函数:linkage,fcluster

1. linkage

def linkage(y, method='single', metric='euclidean', optimal_ordering=False):

函数功能解释:执行层次/聚集聚类

  1. 参数(Parameters):

    • y:输入y可以是 1 维凝聚距离矩阵(距离向量)或 2 维观测矢量数组(坐标点的矩阵)。
    • method:method是指计算类间距离的方法,有如下几种方法:single,complete,average,weighted,centroid,ward
      • single:最近邻,把类与类间距离最近的作为类间距
        从簇 u 和 簇 v 中找到一对距离最近的点的距离作为簇 u 和簇 v 的距离:在这里插入图片描述
        在这里插入图片描述
      • complete:最远邻,把类与类间距离最远的作为类间距
        从簇 u 和 簇 v 中找到一对距离最远的点的距离作为簇 u 和簇 v 的距离:在这里插入图片描述在这里插入图片描述
      • average:平均距离,类与类间所有pairs距离的平均
        如簇 u 中有若干个点 i,簇 v 中有若干个 j 点,簇 u 和簇 v的距离为:在这里插入图片描述 在这里插入图片描述
      • weighted:在压缩距离矩阵上执行加权/ WPGMA链接
        如簇u由簇 s 和簇 t 组成,那么簇 u 到 簇 v 的距离为:在这里插入图片描述
        在这里插入图片描述
      • centroid:质心距离,把类与类中的质心间距离作为类间距在这里插入图片描述
      • ward:将要合并的群集的方差最小化。
  2. 返回值(Returns):

    • Z(ndarray):层次聚类编码为一个linkage矩阵。

      Z共有四列组成,第 1 字段与第 2 字段分别为聚类簇的编号,在初始距离前每个初始值被从0~n-1进行标识,每生成一个新的聚类簇就在此基础上增加一对新的聚类簇进行标识,第 3 个字段表示前两个聚类簇之间的距离,第 4 个字段表示新生成聚类簇所包含的元素的个数。

  3. 参考资料:https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.linkage.html#scipy.cluster.hierarchy.linkage


2. fcluster

def fcluster(Z, t, criterion='inconsistent', depth=2, R=None, monocrit=None):

函数功能解释:从给定链接矩阵定义的层次聚类中形成平面聚类

  1. 参数(Parameters):
    • Z:Z是linkage得到的矩阵,记录了层次聚类的层次信息;
    • t:是一个聚类的阈值
    • criterionstr:形成扁平簇的准则
      • inconsistent:
      • distance:以簇之间的距离作为划分准则
  2. 返回值(Returns):
    fcluster(ndarray):长度为n的数组。 T [i]是原始观测值 i 所属的平面簇数。
  3. 详细参考:https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.fcluster.html#scipy.cluster.hierarchy.fcluster

(二) 示例含完整算法

如对以下 5 个点进行凝聚层次聚类

xy
点012
点123
点2-33
点3-2-1
点45-1

在坐标轴上的位置:在这里插入图片描述层次聚类结果的聚类树为:在这里插入图片描述

完整算法如下:

python">#!/usr/bin/env python
# encoding: utf-8
'''
@Author  : pentiumCM
@Email   : 842679178@qq.com
@Software: PyCharm
@File    : sci_cluster.py
@Time    : 2020/4/15 22:21
@desc	 : scipy实现层次聚类
'''

import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage, fcluster

from matplotlib import pyplot as plt

data = np.array([[1, 2], [2, 3], [-3, 3], [-2, -1], [5, -1]])

# 画点
plt.scatter(x=data[:, 0:1], y=data[:, 1:2], marker='.', color='red')
n = np.arange(data.shape[0])
for i, txt in enumerate(n):
    plt.annotate(txt, (data[i:i + 1, 0:1], data[i:i + 1, 1:2]))
plt.show()

# 1. 层次聚类
# linkage方法用于计算两个聚类簇s和t之间的距离d(s,t)
# 层次聚类编码为一个linkage矩阵。
Z = linkage(data, 'average')
print("聚类过程:", Z)

# 从给定链接矩阵定义的层次聚类中形成平面聚类
# distance:以距离为划分距离的准则
f = fcluster(Z, 4, 'distance')
print("平面聚类结果:", f)

fig = plt.figure(figsize=(5, 3))
# 将层级聚类结果以树状图表示出来
dn = dendrogram(Z)
plt.show()

算法运行结果:

python">聚类过程: [[0.         1.         1.41421356 2.        ]
 [2.         3.         4.12310563 2.        ]
 [5.         6.         4.75565014 4.        ]
 [4.         7.         6.48606798 5.        ]]
平面聚类结果: [1 1 2 3 4]

聚类的主要信息在 Z = linkage(data, ‘average’)中。
Z共有四列组成,第 1 字段与第 2 字段分别为聚类簇的编号,在初始距离前每个初始值被从0~n-1进行标识,每生成一个新的聚类簇就在此基础上增加一对新的聚类簇进行标识,第 3 个字段表示前两个聚类簇之间的距离,第 4 个字段表示新生成聚类簇所包含的元素的个数。


层次聚类可以一次性聚类出所有的情况,当生成出聚类树的结果时,可以通过在聚类树上画水平线(例如在上面算法中,水平线是以簇之间距离为准则)来选择聚成几类的结果。如用户需要聚成两类:在这里插入图片描述只需要从上往下画出如上图的水平线来判断聚成两类的结果,可以看出两类的结果,一类为 4,另一类为0、1、2、3。
如果需要聚成3类,只需要将水平线往下平移即可知道聚成三类的结果。


二、sklearn实现

(一) 函数说明

sklearn库下的层次聚类是在sklearn.cluster的 AgglomerativeClustering中:

python">def __init__(self, n_clusters=2, affinity="euclidean",
             memory=None,
             connectivity=None, compute_full_tree='auto',
             linkage='ward', distance_threshold=None):

AgglomerativeClustering 类的构造函数的参数有 簇的个数 n_clusters,连接方法 linkage,连接度量选项 affinity 三个重要参数:

  • n_clusters:用户指定需要聚成几类。

  • linkage:选择计算簇与簇之间距离的策略,包含:ward,complete,average,single

    • ward:将要合并的群集的方差最小化。
    • complete:完全距离/最大距离,使用两组中所有观察值之间的最大距离。
    • single:最小距离,使用两组中所有观测值之间的最小距离。
    • average:平均距离,使用两组的每个观测值的距离平均值。
  • affinity:是一个簇间距离的计算方法。 可以是 “ euclidean(欧式距离)”,“ l1”,“ l2”,“manhattan(曼哈顿距离)”,“cosine(余弦)” 或 “precomputed(预先计算)”。

    • 如果链接为“ward”,则仅接受“欧式距离”。

    • 如果 “precomputed(预先计算)”,则需要距离矩阵作为拟合方法的输入。

      距离矩阵 的生成方法:假设用户有 n 个观测点,那么先依次构造这 n 个点两两间的距离列表,即长度为 n*(n-1)/2 的距离列表,然后通过 scipy.spatial.distance 的 dist 库的 squareform 函数就可以构造距离矩阵了。这种方式的好处是用户可以使用自己定义的方法计算任意两个观测点的距离,然后再进行聚类。后面也会给出基于自定义的距离矩阵进行的聚类算法。

参考资料:源码文档


(二) 完整算法

python">#!/usr/bin/env python
# encoding: utf-8
'''
@Author  : pentiumCM
@Email   : 842679178@qq.com
@Software: PyCharm
@File    : sklearn_hierarchical_cluster.py
@Time    : 2020/4/23 15:00
@desc	 : sklearn的层次聚类
'''

import numpy as np
from matplotlib import pyplot as plt

from sklearn.cluster import AgglomerativeClustering

data = np.array([[1, 2], [2, 3], [-3, 3], [-2, -1], [5, -1]])

# 画点
plt.scatter(x=data[:, 0:1], y=data[:, 1:2], marker='.', color='red')
n = np.arange(data.shape[0])
for i, txt in enumerate(n):
    plt.annotate(txt, (data[i:i + 1, 0:1], data[i:i + 1, 1:2]))
plt.show()

# 训练模型
ac = AgglomerativeClustering(n_clusters=3, affinity='euclidean', linkage='average')
clustering = ac.fit(data)

print("每个数据所属的簇编号", clustering.labels_)
print("每个簇的成员", clustering.children_)

算法运行结果:

python">每个数据所属的簇编号 [2 2 0 0 1]
每个簇的成员 [[0 1]
 			[2 3]
 			[5 6]
 			[4 7]]

借助 scipy 生成的聚类树,我们来理解一下聚类的结果:

在这里插入图片描述
clustering.labels_:表示每个数据所属于哪一个簇。
  [2 2 0 0 1]:表示数据0、1分为一簇,2、3分为一簇,4分为一簇。
clustering.children_:表示每个簇中有哪些元素。
  [[0 1] [2 3] [5 6] [4 7]]:首先将数据初始化为簇 0 ~ n-1,然后簇0、1合并为簇5,簇2、3合并为簇6,簇5、6合并为簇7,最后簇4、7合并。


补充基于预计算(precomputed)的距离矩阵的算法

完整算法如下:

python">#!/usr/bin/env python
# encoding: utf-8
'''
@Author  : pentiumCM
@Email   : 842679178@qq.com
@Software: PyCharm
@File    : sklearn_hierarchical_cluster.py
@Time    : 2020/4/23 15:00
@desc	 : sklearn的层次聚类
'''

import numpy as np
from matplotlib import pyplot as plt

from sklearn.cluster import AgglomerativeClustering

from sklearn.metrics.pairwise import euclidean_distances
import scipy.spatial.distance as dist
from scipy.cluster.hierarchy import dendrogram, linkage

data = np.array([[1, 2], [2, 3], [-3, 3], [-2, -1], [5, -1]])

# 画点
plt.scatter(x=data[:, 0:1], y=data[:, 1:2], marker='.', color='red')
n = np.arange(data.shape[0])
for i, txt in enumerate(n):
    plt.annotate(txt, (data[i:i + 1, 0:1], data[i:i + 1, 1:2]))
plt.show()

# 聚类方式一
# 训练模型
ac = AgglomerativeClustering(n_clusters=3, affinity='euclidean', linkage='average')
clustering = ac.fit(data)

print("每个数据所属的簇编号:", clustering.labels_)
print("每个簇的成员:", clustering.children_)

# 聚类的方式二
# 自定义距离矩阵
num = data.shape[0]
dist_matrix = np.mat(np.zeros((num, num)))
for i in range(num):
    for j in range(i, num):
        distence = euclidean_distances(data[i:i + 1], data[j:j + 1])
        dist_matrix[i:i + 1, j:j + 1] = distence
        dist_matrix[j:j + 1, i:i + 1] = dist_matrix[i:i + 1, j:j + 1]

# 基于自定义的聚类矩阵进行聚类
model = AgglomerativeClustering(n_clusters=3, affinity='precomputed', linkage='average')
clustering2 = model.fit(dist_matrix)

print("自定义距离矩阵聚类方式:")
print("每个数据所属的簇编号:", clustering2.labels_)
print("每个簇的成员:", clustering2.children_)

# 调整距离矩阵的形状
dist_matrix = dist.squareform(dist_matrix)

# linkage方法用于计算两个聚类簇s和t之间的距离d(s,t)
# 层次聚类编码为一个linkage矩阵。
Z = linkage(dist_matrix, 'average')
print("聚类过程:", Z)

# 将层级聚类结果以树状图表示出来
fig = plt.figure(figsize=(5, 3))
dn = dendrogram(Z)
plt.show()

算法运行结果:

python">每个数据所属的簇编号: [2 2 0 0 1]
每个簇的成员: [[0 1]
			  [2 3]
			  [5 6]
			  [4 7]]
自定义距离矩阵聚类方式:
每个数据所属的簇编号: [2 2 0 0 1]
每个簇的成员: [[0 1]
			  [2 3]
			  [5 6]
			  [4 7]]
聚类过程: [[0.         1.         1.41421356 2.        ]
		  [2.         3.         4.12310563 2.        ]
		  [5.         6.         4.75565014 4.        ]
		  [4.         7.         6.48606798 5.        ]]

上面的算法包含了sklearn的两种聚类方式,方式二为预计算的方式:算法预先计算了 期初各个数据点之间的距离矩阵dist_matrix,然后在聚类时,affinity=‘precomputed’。


对比之下,对于层次聚类的方便理解的方式,大家可以采用scipy的方式。


参考资料

  • 层次聚类的算法实现博客:
    • https://blog.csdn.net/andy_shenzl/article/details/83783469#2%E3%80%81scipy%E5%AE%9E%E7%8E%B0
    • https://blog.csdn.net/weixin_44530236/article/details/89160137
  • sklearn / scipy 帮助文档:
    • https://scikit-learn.org/stable/modules/generated/sklearn.cluster.AgglomerativeClustering.html#sklearn.cluster.AgglomerativeClustering
    • https://docs.scipy.org/doc/scipy/reference/cluster.hierarchy.html#module-scipy.cluster.hierarchy

http://www.niftyadmin.cn/n/1663438.html

相关文章

Powershell foreach

1234567Get-ChildItem | select fullname | Out-File temp.txt $file Get-Content "temp.txt" foreach ($pro in $file) { Write-Host $pro } 本文转自bard_zhang51CTO博客,原文链接: http://blog.51cto.com/timefiles/1753540,如…

思科ASA系列防火墙相关配置--8.4版

思科ASA系列防火墙相关配置 8.4版 1.主机名,ip地址配置 配置完ip地址后直连的设备可以互相ping通 (config)# hostname ASA2 //主机名 (config)# interface gigabitEthernet 0 //进入接口配置 (config-if)# ip address 222.222.222.2 255.255.255.0 //配置ip地址 …

非暴力沟通

周首送我的这本书《非暴力沟通》(NVC,Nonviolent Communication),是马歇尔卢森堡博士发明的一种沟通方式,全书强调了四要素,共8个字:观察、感受、需要、请求。就是要诚实、清晰地表达自己&#…

Redis常用命令整理

doc 环境下使用命令:keys 命令? 匹配一个字符* 匹配任意个(包括0个)字符[] 匹配括号间的任一个字符,可以使用 "-" 符号表示一个范围,如 a[b-d] 可以匹配 "ab","ac","ad&…

【Maven学习笔记】2:在Eclipse中解决getManifest错误,运行Maven Web项目

解决MavenArchiver.getManifest错误 刚构建好Maven的项目雏形,就出现了报错: 在Help->Install New Software中,点击add添加名为MavenArchiver的插件: https://otto.takari.io/content/sites/m2e.extras/m2eclipse-mavenar…

【Maven学习笔记】3:在Eclipse的Maven项目下pom.xml中添加Spring MVC的jar包构建项目

添加jar包 Maven的方便之处就在于不用手动下载依赖&#xff0c;只要在pom.xml中书写要用的jar包&#xff0c;就会连带它要使用的依赖一起下载。 在pom.xml文件中&#xff0c;<properties>标签内添加变量&#xff0c;用来保存后面要添加的jar包的版本&#xff1a; <!…

【Maven学习笔记】4:在IDEA中使用Maven搭建SSM空项目

创建Maven webapp项目雏形 勾选上从原形构建&#xff1a; 同样要提供groupId、artifactId、version这三个必备信息&#xff1a; 指明Maven目录、配置文件的位置、仓库目录(可从配置文件读取)&#xff1a; 项目名称、项目根目录位置&#xff1a; 点击完成后&#x…

在IDEA中使用SSM框架(Spring MVC+Spring+MyBatis)的例子

继在IDEA中使用Maven搭建SSM空项目以后&#xff0c;在这个搭建好的SSM框架上做一个简易的登录例子。 目录结构 大体结构 展开结构 代码 jdbc.properties driverClassscom.mysql.jdbc.Driver jdbcUrljdbc:mysql://localhost:3306/test_mbts usernameroot password3838438#定…