改进的 K-Means 聚类方法介绍

引言

数据科学的一个中心假设是,紧密度表明相关性。彼此“接近”的数据点是相似的。如果将年龄、头发数量和体重绘制在空间中,很可能许多人会聚集在一起。这就是 k 均值聚类背后的直觉。

我们随机生成 K 个质心,每个簇一个,并将每个数据点分配给与该数据点最近的质心对应的簇。然后,我们生成新的质心,每个质心都是属于该簇的所有点的平均值。然后重复这个过程直到收敛。

我们可以使用欧几里德距离作为距离度量并计算每个数据点与质心之间的距离。

def cross_euclidean_distance(x, y=None):y = x if y is None else y assert len(x.shape) >= 2assert len(y.shape) >= 2return euclidean_distance(x[..., :, None, :], y[..., None, :, :])

这样我们就可以执行 K 均值聚类算法的核心了。

def fit(self, X):cluster_ind = np.repeat(0, X.shape[0])idx = np.random.randint(X.shape[0], size=self.m_clusters)self.centroids = X.loc[idx].to_numpy()cross_dist = cross_euclidean_distance(X.to_numpy(), self.centroids)cluster_ind = np.argmin(cross_dist, axis = 1)for _ in range(self.max_iter):#Calculating new centroidsfor i in range(self.m_clusters):X_i = X[cluster_ind == i]self.centroids[i] = X_i.mean(axis = 0).to_numpy()#Assigne data points to new cluster and check if cluster assignment chengescross_dist = cross_euclidean_distance(X.to_numpy(), self.centroids)cluster_ind_new = np.argmin(cross_dist, axis = 1)if not (cluster_ind_new == cluster_ind).any():breakcluster_ind = cluster_ind_new

K-means算法保证收敛,但可能不会收敛到全局最优。相反,它经常陷入局部最优。本文的其余部分将致力于解决这个问题。

根据种子的不同,算法可能会陷入局部最优

关注公众号 [小Z的科研日常] ,查看最新技术分享。

简单的解决方案

最简单的解决方案就是使用不同的起始质心多次运行算法,然后选择最佳的聚类分配。

为了有效地做到这一点,我们需要一种衡量方法来量化集群分配的好坏。其中一种衡量标准是欧几里得畸变。每个点到质心的平均距离对应于它们分配到的簇。运行该算法几次并保存欧几里得失真最低的算法,并希望它是全局最优的。

def euclidean_distortion(X, z):X, z = np.asarray(X), np.asarray(z)assert len(X.shape) == 2assert len(z.shape) == 1assert X.shape[0] == z.shape[0]distortion = 0.0for c in np.unique(z):Xc = X[z == c]mu = Xc.mean(axis=0)distortion += ((Xc - mu) ** 2).sum()return distortion

更智能的采样

幸运的是,我们可以做得更好。这种方法的主要问题是计算成本较高。为了缓解这个问题,我们可以调整起始条件,以便我们更有可能找到全局最优值。为了了解如何实现,让我们看一个玩具问题。

我们希望我们的算法找到总共 10 个数据组。看起来有 10 个不同的簇。当我们运行算法时,我们发现我们可能会得到一个或两个集群错误。

使用 K = 10 运行 K 均值聚类后的聚类分配。我们看到分配并不完美。紫色簇太大,而黄色和青绿色簇争夺同一组。

两个组成为一个超级集群,而另一个组则由两个集群共享。发生这种情况可能是因为两个初始质心靠得太近。为了减少这种情况发生的可能性,我们可以在如何对初始质心进行采样方面变得更加智能。

我们可以不从数据中均匀采样质心,而是从加权分布中顺序采样质心,其中每个权重由到已采样质心的距离决定。这确保了我们不太可能对接近已采样质心的质心进行采样。其算法很简单。在这里,我简单地将概率视为每个数据点到最近质心的归一化距离。这确保我们不会对同一个数据点进行两次采样。

idx = np.random.choice(range(X.shape[0]), size=1)
centroids = X.loc[idx].to_numpy()
while len(centroids)<self.m_clusters:distances = cross_euclidean_distance(centroids, X.to_numpy())prob_vec = distances.min(axis = 0)prob_vec = prob_vec**2/np.sum(prob_vec**2)#Note: zero proability that new centorid is allready a centroididx = np.append(idx, np.random.choice(X.shape[0], size=1, p = prob_vec)) centroids = X.loc[idx].to_numpy()self.centroids = centroids

智能分配

然而,上述方法可能仍然有些不足。我们只是增加了不出现错误初始配置的机会。为了确保我们得到全局最大值的分配,我们仍然需要运行算法多次。这样做的问题是,每次重新启动算法时,我们都会丢弃进度。更好的方法是找出我们当前任务的问题所在以及如何改进。考虑这个集群分配。

这个簇分配非常糟糕,有两个超级簇和两对质心,彼此距离太近。

黄色和青绿色的簇占据了太多的空间,而棕色、紫色、粉色和橙色的簇则占据了很少的空间。通过智能分配算法,我们可以识别两个最近的质心,并将其中一个移动到最需要的位置。

也就是说,到距质心最远的点。如果我们进行了太多的跳跃,我们只需保存最佳的收敛统计数据,就像之前的重复过程一样。这个的实现是在下面的代码中完成的。

n_worst = int(round(X.shape[0]*self.worst_prec))
best_reroll_centroids = self.centroids
best_reroll_distortion = euclidean_distortion(X, cluster_ind)
for i in range(self.n_rerolls):# Caculate new centroidsfor i in range(self.m_clusters):X_i = X[cluster_ind == i]self.centroids[i] = X_i.mean(axis = 0).to_numpy()# Find the two centroids that are closest and pick the centoid with the lowest average distance to other centroidscentroid_dist = cross_euclidean_distance(self.centroids)cetorid_dist_inf = centroid_dist + np.diag(np.repeat(np.inf, centroid_dist.shape[0])) # Add inf to diagworst_pair = np.unravel_index((cetorid_dist_inf).argmin(), cetorid_dist_inf.shape) # Find indexes of worst pairworst_ind = worst_pair[0] if (np.mean(centroid_dist[worst_pair[0]])<np.mean(centroid_dist[worst_pair[1]])) else worst_pair[1]# Assign the old centroid to be the one closest to the poinst that are furthest away from the current centroidsmin_dists = np.min(cross_dist, axis = 1)high_dists_ind = np.argpartition(min_dists, -n_worst)[-n_worst:]X_high = X.loc[high_dists_ind]self.centroids[worst_ind] = X_high.mean(axis = 0).to_numpy()# Itterate until convergencefor _ in range(self.max_iter):#Calculating new centroidsfor i in range(self.m_clusters):X_i = X[cluster_ind == i]self.centroids[i] = X_i.mean(axis = 0).to_numpy()#Assigne data points to new cluster and check if cluster assignment chengescross_dist = cross_euclidean_distance(X.to_numpy(), self.centroids)cluster_ind_new = np.argmin(cross_dist, axis = 1)if not (cluster_ind_new == cluster_ind).any():breakcluster_ind = cluster_ind_newdistortion = euclidean_distortion(X, cluster_ind)if distortion<best_reroll_distortion:best_reroll_distortion = distortionbest_reroll_centroids = self.centroidsself.centroids = best_reroll_centroids 

下图显示了正在运行的算法。首先,粉红色的簇被移动。

粉红色的质心已经跳到绿松石色的星团上

我们看到粉红色的质心已经跳到绿松石色的星团上。此配置仍远未达到最佳状态。紫色和粉红色的簇所占的量太少,而黄色和绿松石色的簇所占的量太多。这可以通过重复该过程几次来解决。

    可以观察到紫色质心跳到粉色簇 

可以观察到紫色质心跳转到黄色质心

通过最后的跳跃,我们可以简单地运行直到收敛,最终获得接近最佳的集群分配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/451007.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聊聊并发编程,另送5本Golang并发编程新书

大家好&#xff0c;我是飞哥&#xff01; 并发编程并不是一个新话题&#xff0c;但是我觉得在近几年以及未来的时间里&#xff0c;并发编程将显得越来越重要。 为什么这样讲&#xff0c;让我们先回到一个基本的问题上来&#xff0c;为什么我们要采用并发编程&#xff1f;关于这…

k8s之安装部署及kuboard发布应用

目录 环境准备 系统规划 配置免密 将桥接的IPv4流量传递到iptables的链 系统基础配置 安装docker 安装docker及基础依赖 配置docker的仓库下载地址 部署k8s 添加阿里云的k8s源 安装kubeadm&#xff0c;kubelet和kubectl 初始化masteer节点 部署node节点 部署flanne…

OpenSSL:configure: error: OpenSSL library not found解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

springboot153相亲网站

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

【Redis】整理

对于现代大型系统而言&#xff0c;缓存是一个绕不开的技术话题&#xff0c;一提到缓存我们很容易想到Redis。 Redis整理&#xff0c;供回顾参考

PHP漏洞查询

CVE - Search CVE List (mitre.org) 美国国家漏洞数据库&#xff08;需要梯子&#xff09; NATIONAL VULNERABILITY DATABASE NVD - Search and Statistics (nist.gov) 基本都能查询到&#xff0c;传结果详情页里面会有一些解决方案的连接 PHP的官方网站 PHP :: Bugs :: Se…

【annie/lux 快速下载哔哩哔哩视频】全网最简单,只需要5步!!!

1.首先 现在annie更名为lux 官网地址&#xff1a;https://github.com/iawia002/lux/releases 2.进入官网之后如图所示 3.下载lux软件 4.下载lux 这里需要说明一下 如果不下载这个的话也可以下载视频 但是视频和音频是分开的&#xff0c;你的视频没有声音 5.下载视频

从宏观上对人工智能(AI)的一些理解

1.人工智能概述 68年前&#xff0c;约翰麦卡锡在“达特茅斯会议”正式提出人工智能概念。直到2023年&#xff0c;ChatGPT掀起全球AI大模型浪潮&#xff0c;英伟达市值一年飙涨2.4倍&#xff0c;真正意义上的“人工智能元年”到来了。 提到人工智能&#x…

【信息抽取 YYDS!】KnowLM:知识图谱 + 大模型,实现更有效的信息抽取和知识管理

KnowLM 知识图谱 大模型&#xff1a;实现信息抽取 KnowLM 原理KnowLM 部署KnowLM 应用1. 命名实体识别&#xff08;NER&#xff09;2. 关系抽取&#xff08;RE&#xff09;3. 事件抽取&#xff08;EE&#xff09; KnowLM 原理 代码&#xff1a;https://github.com/zjunlp/Kno…

隧道穿透:常规反弹、加密反弹

目录 1、常规反弹 &#xff08;1&#xff09;Windows正向连接shell &#xff08;2&#xff09;Windows反向连接shell &#xff08;3&#xff09;Linux正向连接shell &#xff08;2&#xff09;利用Linux自带bash反弹Shell 2、加密反弹 1、常规反弹 假设在内网环境中发现…

GPGPU面临的工程困境闲聊

作者&#xff1a;蒋志强 本人同意他人对我的文章引用&#xff0c;但请在引用时注明出处&#xff0c;谢谢&#xff0e;作者&#xff1a;蒋志强 0.前言 2007年作为GPGPU的工程界元年至今&#xff0c;已经发展了接近小二十年了。这个领域是如此的重要&#xff0c;几乎影响了工业…

LangChain 81 LangGraph 从入门到精通三

LangChain系列文章 LangChain 60 深入理解LangChain 表达式语言23 multiple chains链透传参数 LangChain Expression Language (LCEL)LangChain 61 深入理解LangChain 表达式语言24 multiple chains链透传参数 LangChain Expression Language (LCEL)LangChain 62 深入理解Lang…