层次聚类python实现_聚类算法之层次聚类(Python实现)
起步
层次聚类( Hierarchical Clustering )是聚类算法的一种,通过计算不同类别的相似度类创建一个有层次的嵌套的树。
层次聚类算法介绍
假设有 n 个待聚类的样本,对于层次聚类算法,它的步骤是:
步骤一:(初始化)将每个样本都视为一个聚类;
步骤二:计算各个聚类之间的相似度;
步骤三:寻找最近的两个聚类,将他们归为一类;
步骤四:重复步骤二,步骤三;直到所有样本归为一类。
整个过程就是建立一棵树,在建立的过程中,可以在步骤四设置所需分类的类别个数,作为迭代的终止条件,毕竟都归为一类并不实际。
聚类之间的相似度
聚类和聚类之间的相似度有什么来衡量呢?既然是空间中的点,可以采用距离的方式来衡量,一般有下面三种:
Single Linkage
又叫做 nearest-neighbor ,就是取两个类中距离最近的两个样本的距离作为这两个集合的距离。这种计算方式容易造成一种叫做 Chaining 的效果,两个 cluster 明明从“大局”上离得比较远,但是由于其中个别的点距离比较近就被合并了,并且这样合并之后 Chaining 效应会进一步扩大,最后会得到比较松散的 cluster 。
Complete Linkage
这个则完全是 Single Linkage 的反面极端,取两个集合中距离最远的两个点的距离作为两个集合的距离。其效果也是刚好相反的,限制非常大。这两种相似度的定义方法的共同问题就是指考虑了某个有特点的数据,而没有考虑类内数据的整体特点。
Average Linkage 这种方法就是把两个集合中的点两两的距离全部放在一起求均值,相对也能得到合适一点的结果。有时异常点的存在会影响均值,平常人和富豪平均一下收入会被拉高是吧,因此这种计算方法的一个变种就是取两两距离的中位数。
python 实现层次聚类
空间中点的距离使用欧式距离:
import math
import numpy as np
def euler_distance(point1: np.ndarray, point2: list) -> float:
"""
计算两点之间的欧拉距离,支持多维
"""
distance = 0.0
for a, b in zip(point1, point2):
distance += math.pow(a - b, 2)
return math.sqrt(distance)
定义聚类数的节点:
class ClusterNode(object):
def __init__(self, vec, left=None, right=None, distance=-1, id=None, count=1):
"""
:param vec: 保存两个数据聚类后形成新的中心
:param left: 左节点
:param right: 右节点
:param distance: 两个节点的距离
:param id: 用来标记哪些节点是计算过的
:param count: 这个节点的叶子节点个数
"""
self.vec = vec
self.left = left
self.right = right
self.distance = distance
self.id = id
self.count = count
vec 表示合并后的聚类中心,是一个点,代表整个聚类的位置;distance 表示左节点和右节点的距离。
计算层次聚类算法的类:
class Hierarchical(object):
def __init__(self, k = 1):
assert k > 0
self.k = k
self.labels = None
def fit(self, x):
nodes = [ClusterNode(vec=v, id=i) for i,v in enumerate(x)]
distances = {}
point_num, future_num = np.shape(x) # 特征的维度
self.labels = [ -1 ] * point_num
currentclustid = -1
while len(nodes) > self.k:
min_dist = math.inf
nodes_len = len(nodes)
closest_part = None # 表示最相似的两个聚类
for i in range(nodes_len - 1):
for j in range(i + 1, nodes_len):
# 为了不重复计算距离,保存在字典内
d_key = (nodes[i].id, nodes[j].id)
if d_key not in distances:
distances[d_key] = euler_distance(nodes[i].vec, nodes[j].vec)
d = distances[d_key]
if d < min_dist:
min_dist = d
closest_part = (i, j)
# 合并两个聚类
part1, part2 = closest_part
node1, node2 = nodes[part1], nodes[part2]
new_vec = [ (node1.vec[i] * node1.count + node2.vec[i] * node2.count ) / (node1.count + node2.count)
for i in range(future_num)]
new_node = ClusterNode(vec=new_vec,
left=node1,
right=node2,
distance=min_dist,
id=currentclustid,
count=node1.count + node2.count)
currentclustid -= 1
del nodes[part2], nodes[part1] # 一定要先del索引较大的
nodes.append(new_node)
self.nodes = nodes
self.calc_label()
def calc_label(self):
"""
调取聚类的结果
"""
for i, node in enumerate(self.nodes):
# 将节点的所有叶子节点都分类
self.leaf_traversal(node, i)
def leaf_traversal(self, node: ClusterNode, label):
"""
递归遍历叶子节点
"""
if node.left == None and node.right == None:
self.labels[node.id] = label
if node.left:
self.leaf_traversal(node.left, label)
if node.right:
self.leaf_traversal(node.right, label)
最后将聚类的列表标记保存于 labels 中。
测试
与 sklearn 进行对比:
iris = datasets.load_iris()
my = Hierarchical(4)
my.fit(iris.data)
print(np.array(my.labels))
sk = cluster.AgglomerativeClustering(4)
sk.fit(iris.data)
print(sk.labels_)
得到输出:
[3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 2 1 2 2 2 2 1 2 2 2 2
2 2 1 1 2 2 2 2 1 2 1 2 1 2 2 1 1 2 2 2 2 2 1 2 2 2 2 1 2 2 2 1 2 2 2 1 2
2 1]
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 3 2 3 2 3 2 3 3 2 3 2 3 2 3 3 2 3 2 2 2 2
2 2 2 0 2 3 3 3 3 2 3 2 2 2 3 3 3 2 3 3 3 3 3 2 3 3 0 2 0 0 0 0 3 0 0 0 0
0 0 2 2 0 0 0 0 2 0 2 0 2 0 0 2 2 0 0 0 0 0 2 2 0 0 0 2 0 0 0 2 0 0 0 2 0
0 2]
结果还算是理想的。
层次聚类的优缺点
优点:
一次性得到聚类树,后期再分类无需重新计算;
相似度规则容易定义;
可以发现类别的层次关系。
缺点:
计算复杂度高,不适合数据量大的;
算法很可能形成链状。
附录
层次聚类python实现_聚类算法之层次聚类(Python实现)相关推荐
- python机器学习手写算法系列——kmeans聚类
从机器学习到kmeans 聚类是一种非监督学习,他和监督学习里的分类有相似之处,两者都是把样本分布到不同的组里去.区别在于,分类分析是有标签的,聚类是没有标签的.或者说,分类是有y的,聚类是没有y的, ...
- java寻优算法_模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径...
模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...
- 风云编程python怎么样_二十年编程语言风云,看Python如何一步步往上爬!
作者 | 周萝卜 来源 | 萝卜大杂烩 年终岁尾了,编程语言也要决出这一年的最佳语言了,会是谁呢,从 TIOBE 上来看,Java.C 和 Python 基本锁定了前三的位置,Java 江湖老大的地位 ...
- 免费学python编程_强力推荐,非常全的 Python编程学习资料(今日免费)
因为大数据和 AI,Python 一跃成为最火的语言,这里推荐几本畅销排行榜上的好书. 有需要在我的头条号,私信我,"Python",即可免费领取. 一.Python基础教程 &l ...
- 量化投资与python语言_在量化投资领域,为什么Python如此受欢迎?
说起Web领域 你立马会想到JavaScript语言,它在Web领域不可撼动:Python也已经在金融量化投资领域占据了重要位置,从各个业务链条都能找到相应的框架实现. 在量化投资(证券和比特币)开源 ...
- 请给出计算231-1的python表达式_计算 2 31 -1 的 Python 表达式是 。_学小易找答案
[填空题]国内教学目标分类的二维层次模型中,教学内容被分为哪五个层次:事实.概念.技能.______.问题解决. [多选题]报表子系统提供的图表格式一般包括? [填空题]激发和维持学生学习动机的模型- ...
- 浪漫的python代码_七夕,最浪漫的Python代码送给陷入爱河的Python男同胞
七夕,最浪漫的Python代码送给陷入爱河的Python男同胞 image.gif 三句话情书,我们听过.如何用python写一段浪漫的代码?可以是简短有韵味的情书式, 也欢迎冗长而效果拔群的万行 ...
- python直线拟合_RANSAC算法详解(附Python拟合直线模型代码)
之前只是简单了解RANSAC模型,知道它是干什么的.然后今天有个课程设计的报告,上去讲了一下RANSAC,感觉这个东西也没那么复杂,所以今天就总结一些RASAC并用Python实现一下直线拟合. RA ...
- flask执行python脚本_如何在Flask中运行python脚本
我有一个Flask脚本,可以创建网站并动态打印一些数据.-打印的数据应来自另一个python脚本. 我目前面临的问题是,如果我将执行python脚本的行放在执行Flask应用程序的行之前,它将运行Py ...
- yaahp层次分析法步骤_综合评价方法之层次分析法,选择再也难不倒你!
在日常生活中, 我们常常面临着各种各样的选择. 比如你想去北京.上海.广州旅游, 但是由于种种原因, 你只能选择一个地点去旅游, 那么哪一种选择是最优的呢? 有没有较为科学的方法帮助我们更好地选择呢? ...
最新文章
- android里的editText怎么用,Android自定义控件EditText使用详解
- 11g RMAN Restore archivelog用法
- python list合并_python中如何合并两个列表
- One Class SVM 对于样本不均衡处理思路——拿出白样本建模,算出outlier,然后用黑去检验效果...
- socket未读消息 如何设计_如何设计IM系统的消息架构?
- 江苏关于领取软考2021年上半年合格证书的通知
- PostgreSQL在何处处理 sql查询之六
- 主机甲采用停等协议向主机乙_TCP/IP 协议——详解篇
- Maven的安装与配置教程
- 票据通的支票管理的账户管理的对应账号支票已使用该怎么重新修改票据打印模板;
- 魔兽世界——暮光高地任务攻略
- 新概念英语第三册单词
- 马云:曾去肯德基面试25人就我没被录用 30多年彷徨成就今天
- 一个简单的python爬虫程序
- (¥1011)-(一千零一拾一元整)输出
- html中点击图标变色,css可变色图标及原理分析
- Google首席决策师告诉你AI和数据科学团队需要哪10种角色?
- 新版RTMP推流协议视频直播点播平台EasyDSS在进行视频直播/录像回看时如何创建视频录像计划?
- 如何在 Excel 中实现区间查找式的 VLOOKUP
- YOLO 对象检测 OpenCV 源代码