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

引言

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

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

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

def cross_euclidean_distance(x, y=None):
    y = x if y is None else y 
    assert len(x.shape) >= 2
    assert len(y.shape) >= 2
    return 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 centroids
        for 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 chenges
        cross_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():
            break
        cluster_ind = cluster_ind_new

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

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

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

简单的解决方案

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

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

def euclidean_distortion(X, z):
    X, z = np.asarray(X), np.asarray(z)
    assert len(X.shape) == 2
    assert len(z.shape) == 1
    assert X.shape[0] == z.shape[0]
    
    distortion = 0.0
    for 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 centroid
    idx = 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 centroids
    for 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 centroids
    centroid_dist = cross_euclidean_distance(self.centroids)
    cetorid_dist_inf = centroid_dist + np.diag(np.repeat(np.inf, centroid_dist.shape[0])) # Add inf to diag
    worst_pair = np.unravel_index((cetorid_dist_inf).argmin(), cetorid_dist_inf.shape) # Find indexes of worst pair
    worst_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 centroids
    min_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 convergence
    for _ in range(self.max_iter):
        #Calculating new centroids
        for 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 chenges
        cross_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():
            break
        cluster_ind = cluster_ind_new
   
    distortion = euclidean_distortion(X, cluster_ind)
    if distortion<best_reroll_distortion:
        best_reroll_distortion = distortion
        best_reroll_centroids = self.centroids
   
self.centroids = best_reroll_centroids 

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

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

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch-ElasticSearch实战-仿京东商城搜索(高亮)

注&#xff1a;此为笔者学习狂神说ElasticSearch的实战笔记&#xff0c;其中包含个人的笔记和理解&#xff0c;仅做学习笔记之用&#xff0c;更多详细资讯请出门左拐B站&#xff1a;狂神说!!! 七、ElasticSearch实战 仿京东商城搜索&#xff08;高亮&#xff09; 1、工程创建…

【tensorflow 版本 keras版本】

#. 安装tensorflow and keras&#xff0c; 总是遇到版本无法匹配的问题。 安装之前先查表 https://master--floydhub-docs.netlify.app/guides/environments/ 1.先确定你的python version 2.再根据下面表&#xff0c;确定安装的tesorflow, keras

JAVA后端上传图片至企微临时素材

1.使用场景 在使用企业微信API接口中&#xff0c;往往开发者需要使用自定义的资源&#xff0c;比如发送本地图片消息&#xff0c;设置通讯录自定义头像等。 为了实现同一资源文件&#xff0c;一次上传可以多次使用&#xff0c;这里提供了素材管理接口&#xff1a;以media_id来…

尝试创建若依系统项目(vue3+element-plus+vite) 持续更新...

若依官网&#xff1a;RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|开源后台系统|RuoYi|RuoYi-Vue|RuoYi-Cloud|RuoYi框架|RuoYi开源|RuoYi视频|若依视频|RuoYi开发文档|若依开发文档|Java开源框架|Java|Spri…

STM32--USART串口(3)数据包

一、前言 在实际的工程中肯会有同时发送多种数据的情况&#xff0c;比如要不停的发送x、y、z分别对应三种不同的数据。xyzxyzxyz&#xff0c;但接收方可能是从中间某个地方开始接收的&#xff0c;这就导致数据错位。所以我们就需要将数据进行分割&#xff0c;打包成一个一个的…

数仓建模维度建模理论知识

0. 思维导图 第 1 章 数据仓库概述 1.1 数据仓库概述 数据仓库是一个为数据分析而设计的企业级数据管理系统。数据仓库可集中、整合多个信息源的大量数据&#xff0c;借助数据仓库的分析能力&#xff0c;企业可从数据中获得宝贵的信息进而改进决策。同时&#xff0c;随着时间的…

Kotlin快速入门系列10

Kotlin的委托 委托模式是常见的设计模式之一。在委托模式中&#xff0c;有两个对象参与处理同一个请求&#xff0c;接受请求的对象将请求委托给另一个对象来处理。与Java一样&#xff0c;Kotlin也支持委托模式&#xff0c;通过关键字by。 类委托 类的委托即一个类中定义的方…

东南亚独立站的黄金机会-东南亚服务器租用托管的选择

作为一个独立站的企业&#xff0c;选择将服务器托管或租用东南亚的服务器是一个明智的决策。东南亚市场是一个适合做独立站的国家。 1、东南亚的社交媒体用户非常活跃。东南亚地区的人口众多&#xff0c;其中很大一部分人使用社交媒体平台进行社交和购物。据统计&#xff0c;东…

喜报|博睿数据算力调度可观测平台荣获信通院“算力服务领航者计划”优秀案例

近日&#xff0c;中国通信标准化协会云计算标准和开源推进委员会2023年度工作总结会暨算力服务工作组成果发布会在京举行。会上&#xff0c;“2023年算力服务领航者计划优秀案例名单”正式公布&#xff0c;博睿数据的核心产品算力调度可观测平台 Bonree ONE成功入选&#xff0c…

WordPress主题YIA的文章页评论内容为什么没有显示出来?

有些WordPress站长使用YIA主题后&#xff0c;在YIA主题设置的“基本”中没有开启“一键关闭评论功能”&#xff0c;而且文章也是允许评论的&#xff0c;但是评论框却不显示&#xff0c;最关键的是文章原本就有的评论内容也不显示&#xff0c;这是为什么呢&#xff1f; 根据YIA主…

获取真实 IP 地址(一):判断是否使用 CDN(附链接)

一、介绍 CDN&#xff0c;全称为内容分发网络&#xff08;Content Delivery Network&#xff09;&#xff0c;是一种网络架构&#xff0c;旨在提高用户对于网络上内容的访问速度和性能。CDN通过在全球各地部署分布式服务器节点来存储和分发静态和动态内容&#xff0c;从而减少…

2024牛客寒假训练营1总结

G题不开long long的后果&#xff0c;即使有思路也没用。(给我气的) E题&#xff0c;不看数据范围的后果&#xff0c;不能一题名取题啊。 using ll long long; void solve() {int n, m;std::cin >> n >> m;std::vector<int>a(n);for (int i 0; i < n; i)…

【python】英语单词文本处理

文章目录 前言一、环境实验所需的库终端指令 二、实现过程Version 1 起源Version 2 listVersion 3 arrayVersion 4 结构化数组Version 5 区分单元且打乱顺序Version 6 可视化 三、txt文件 前言 缘起自懒得考小孩儿单词&#xff0c;最终效果如图&#xff1a; 本文记录了英语单词…

2024美赛数学建模B题思路分析 - 搜索潜水器

1 赛题 问题B&#xff1a;搜索潜水器 总部位于希腊的小型海上巡航潜艇&#xff08;MCMS&#xff09;公司&#xff0c;制造能够将人类运送到海洋最深处的潜水器。潜水器被移动到该位置&#xff0c;并不受主船的束缚。MCMS现在希望用他们的潜水器带游客在爱奥尼亚海底探险&…

react 之 useCallback

简单讲述下useCallback的使用方法&#xff0c;useCallback也是用来缓存的&#xff0c;只不过是用于做函数缓存 // useCallbackimport { memo, useCallback, useState } from "react"const Input memo(function Input ({ onChange }) {console.log(子组件重新渲染了…

物流自动化移动机器人|HEGERLS三维智能四向穿梭车助力优化企业供应链

智能化仓库/仓储贯穿于物流的各个环节&#xff0c;不局限于存储、输送、分拣、搬运等单一作业环节的自动化&#xff0c;更多的是利用科技手段实现整个物流供应链流程的自动化与智能化&#xff0c;将传统自动化仓储物流各环节进行多维度的有效融合。 例如在数智化物流仓储的建设…

OpenHarmony—Hap包签名工具

概述 为了保证OpenHarmony应用的完整性和来源可靠&#xff0c;在应用构建时需要对应用进行签名。经过签名的应用才能在真机设备上安装、运行、和调试。developtools_hapsigner仓 提供了签名工具的源码&#xff0c;包含密钥对生成、CSR文件生成、证书生成、Profile文件签名、Ha…

华为数通方向HCIP-DataCom H12-821题库(单选题:401-420)

第401题 R1的配置如图所示,此时在R1查看FIB表时,关于目的网段192.168.1.0/24的下跳是以下哪一项? A、10.0.23.3 B、10.0.12.2 C、10.0.23.2 D、10.0.12.1 【答案】A 【答案解析】 该题目考查的是路由的递归查询和 RIB 以及 FIB 的关系。在 RIB 中,静态路由写的是什么,下…

Node.js之内存限制理解_对处理前端打包内存溢出有所帮助

Node.js内存限制理解_对处理前端打包内存溢出有所帮助 文章目录 Node.js内存限制理解_对处理前端打包内存溢出有所帮助Node.js内存限制1. 查看Node.js默认内存限制1. Ndos.js_V20.10.02. Node.js_V18.16.0 2. V8引擎垃圾回收相关Heap organization堆组织 Node.js内存限制 默认情…

(十二)springboot实战——SSE服务推送事件案例实现

前言 SSE&#xff08;Server-Sent Events&#xff0c;服务器推送事件&#xff09;是一种基于HTTP协议的服务器推送技术。它允许服务器向客户端发送异步的、无限长的数据流&#xff0c;而无需客户端不断地轮询或发起请求。这种技术可以用来实现实时通信、在线聊天、即时更新等功…