聚类算法:Kmeans和Kmeans++算法精讲

news2024/9/28 7:21:56

前言

其实Kmesns聚类算法在YOLOv2(【YOLO系列】YOLOv2论文超详细解读(翻译 +学习笔记))中我们就见到了,那时候只是简单地了解了一下。后来在这学期的数据挖掘课程的期末汇报中,我又抽中了这个算法,于是又重新学习了一遍。另外最近在看一些改进的论文,很多摘要中也都提到将Kmeans改为Kmeans++作为创新点(主要是YOLO中对anchor做改进,叫作多尺度自适应锚框初始化)。下面就让我们具体了解一下Kmeans和Kmeans++算法吧!


目录

前言

一、聚类 

1.1 概念

1.2 一般过程

1.3 分类 

二、Kmeans算法

2.1原理

2.2算法步骤

2.3k值确定

2.3.1先验法

2.3.2手肘法

2.4代码实现

2.5优缺点

三、Kmeans++算法

3.1原理

3.2算法步骤

3.3代码实现

3.4优缺点

一、聚类 

1.1 概念

聚类(Clustering) 是按照某个特定标准(如距离)把一个数据集分割成不同的类或簇,使得同一个簇内的数据对象的相似性尽可能大,同时不在同一个簇中的数据对象的差异性也尽可能地大。也就是说,聚类后同一类的数据尽可能聚集到一起,不同类数据尽量分离。

聚类和分类

  • 聚类(Clustering):是指把相似的数据划分到一起,具体划分的时候并不关心这一类的标签,目标就是把相似的数据聚合到一起,聚类是一种无监督学习(Unsupervised Learning)方法。
  • 分类(Classification):是把不同的数据划分开,其过程是通过训练数据集获得一个分类器,再通过分类器去预测未知数据,分类是一种监督学习(Supervised Learning)方法。 

 1.2 一般过程

  •   ①数据准备:包括特征标准化和降维;
  •   ②特征选择:从最初的特征中选择最有效的特征,并将其存储于向量中;
  •   ③特征提取:通过对所选择的特征进行转换形成新的突出特征;
  •   ④聚类(或分组):首先选择合适特征类型的某种距离函数(或构造新的距离函数)进行接近程度的度量,而后执行聚类或分组;
  •   ⑤聚类结果评估:是指对聚类结果进行评估,评估主要有3种:外部有效性评估、内部有效性评估和相关性测试评估。

1.3 分类 


二、Kmeans算法

2.1原理

Kmeans 算法是一种常用的聚类算法,它是基于划分方法聚类的。它的原理是将数据划分为k个簇,每个簇由距离中心最近的数据点组成,基于计算样本与中心点的距离归纳各簇类下的所属样本,迭代实现样本与其归属的簇类中心的距离为最小的目标。

简单来说,Kmeans 算法就是通过不断地调整簇的中心点,并将数据点指派到距离它最近的中心点所在的簇,来逐步将数据划分成若干个簇。

常见目标函数:


2.2算法步骤

 算法执行步骤如下:

  1. 选取K个点做为初始聚集的簇心(也可选择非样本点);
  2. 分别计算每个样本点到 K个簇核心的距离(这里的距离一般取欧氏距离或余弦距离),找到离该点最近的簇核心,将它归属到对应的簇;
  3. 所有点都归属到簇之后, M个点就分为了 K个簇。之后重新计算每个簇的重心(平均距离中心),将其定为新的“簇核心”;
  4. 反复迭代 2 - 3 步骤,直到达到某个中止条件。

【注意】常用的中止条件有迭代次数最小平方误差MSE簇中心点变化率


2.3k值确定

Kmeans划分k个簇,不同k值的情况对最终结果的影响至关重要,不同的k值会带来不同的结果,如下图所示:

 一般情况下,我们确定k值常用两种方法:先验法、手肘法


2.3.1先验法

先验法比较简单,就是凭借着业务知识确定k的取值。比如对于iris花数据集,我们大概知道有三种类别,可以按照k=3做聚类验证。从下图可看出,对比聚类预测与实际的iris种类是比较一致的。 

 

 


2.3.2手肘法

可以知道k值越大,划分的簇群越多,对应的各个点到簇中心的距离的平方的和(类内距离,WSS)越低,我们通过确定WSS随着K的增加而减少的曲线拐点,作为K的取值。


2.4代码实现

Kmeans具体代码如下:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd


def assignment(df, center, colmap):
    # 计算所有样本分别对K个类别中心点的距离
    for i in center.keys():
        df["distance_from_{}".format(i)] = np.sqrt((df["x"] - center[i][0]) ** 2 + (df["y"] - center[i][1]) ** 2)

    distance_from_centroid_id = ['distance_from_{}'.format(i) for i in center.keys()]
    df["closest"] = df.loc[:, distance_from_centroid_id].idxmin(axis=1)  # "closest"列表示每个样本点离哪个类别的中心点距离最近
    print(df["closest"])
    df["closest"] = df["closest"].map(lambda x: int(x.lstrip('distance_from_')))
    df["color"] = df['closest'].map(lambda x: colmap[x])
    return df


def update(df, centroids):
    # 更新K个类别的中心点
    for i in centroids.keys():
        # 每个类别的中心点为 属于该类别的点的x、y坐标的平均值
        centroids[i][0] = np.mean(df[df['closest'] == i]['x'])
        centroids[i][1] = np.mean(df[df['closest'] == i]['y'])
    return centroids


def main():
    df = pd.DataFrame({
        'x': [12, 20, 28, 18, 10, 29, 33, 24, 45, 45, 52, 51, 52, 55, 53, 55, 61, 64, 69, 72, 23],
        'y': [39, 36, 30, 52, 54, 20, 46, 55, 59, 63, 70, 66, 63, 58, 23, 14, 8, 19, 7, 24, 77]
    })
    k = 3

    # 一开始随机指定 K个类的中心点
    center = {
        i: [np.random.randint(0, 80), np.random.randint(0, 80)]
        for i in range(k)
    }

    colmap = {0: "r", 1: "g", 2: "b"}
    df = assignment(df, center, colmap)

    for i in range(10):  # 迭代10次
        closest_center = df['closest'].copy(deep=True)
        center = update(df, center)  # 更新K个类的中心点
        df = assignment(df, center, colmap)  # 类别中心点更新后,重新计算所有样本点到K个类别中心点的距离
        if closest_center.equals(df['closest']):  # 若各个样本点对应的聚类类别不再变化,则结束聚类
            break

    plt.scatter(df['x'], df['y'], color=df['color'], alpha=0.5, edgecolor='b')
    for j in center.keys():
        plt.scatter(*center[j], color=colmap[j], linewidths=6)
    plt.xlim(0, 80)
    plt.ylim(0, 80)
    plt.show()


if __name__ == '__main__':
    main()

实现效果:


2.5优缺点

优点:

  • 理解容易,聚类效果不错
  • 处理大数据集的时候,该算法可以保证较好的伸缩性和高效率
  • 当簇近似高斯分布的时候,效果非常不错

缺点:

  • K值是用户给定的,在进行数据处理前,K值是未知的,给定合适的 k 值,需要先验知识,凭空估计很困难,或者可能导致效果很差
  • 对初始簇中心点是敏感的
  • 不适合发现非凸形状的簇或者大小差别较大的簇
  • 特殊值(离群值或称为异常值)对模型的影响比较大
     

三、Kmeans++算法

3.1原理

原始Kmeans算法最开始随机选取数据集中k个点作为聚类中心,k个初始化的质心的位置选择对最后的聚类结果和运行时间都有很大的影响,因此需要选择合适的k个质心。如果仅仅是完全随机的选择,有可能导致算法收敛很慢。Kmeans++算法主要对对K-Means初始值选取的方法的优化。也就是说,Kmeans++算法与Kmeans算法最本质的区别是在k个聚类中心的初始化过程。


3.2算法步骤

其实通过上面的介绍,我们知道了 Kmeans++算法和Kmeans算法就是选择一开始的k个聚类中心点的方法有差别而已。其初始点的选择过程如下:

  1. 从数据点中随机选择一个中心。
  2. 对于每个数据点x,计算D(x),即x与已经选择的最接近中心之间的距离。
  3. 使用加权概率分布随机选择一个新的数据点作为新的中心,其中选择点 x 的概率与D(x)^2成正比。
  4. 重复步骤2和3,直到选择了K个中心。

其余训练过程与KMeans一致。


3.3代码实现

Kmeans++具体代码如下:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import random


def select_center(first_center, df, k, colmap):
    center = {}
    center[0] = first_center

    for i in range(1, k):
        df = assignment(df, center, colmap)
        sum_closest_d = df.loc[:, 'cd'].sum()  # cd = 最近中心点的距离。把所有样本点对应最近中心点的距离都加在一起
        df["p"] = df.loc[:, 'cd'] / sum_closest_d
        sum_p = df["p"].cumsum()

        # 下面是轮盘法取新的聚类中心点
        next_center = random.random()
        for index, j in enumerate(sum_p):
            if j > next_center:
                break
        center[i] = list(df.iloc[index].values)[0:2]

    return center


def assignment(df, center, colmap):
    # 计算所有样本分别对K个类别中心点的距离
    for i in center.keys():
        df["distance_from_{}".format(i)] = np.sqrt((df["x"] - center[i][0]) ** 2 + (df["y"] - center[i][1]) ** 2)

    distance_from_centroid_id = ['distance_from_{}'.format(i) for i in center.keys()]
    df["closest"] = df.loc[:, distance_from_centroid_id].idxmin(axis=1)  # "closest"列表示每个样本点离哪个类别的中心点距离最近
    df["cd"] = df.loc[:, distance_from_centroid_id].min(axis=1)
    df["closest"] = df["closest"].map(lambda x: int(x.lstrip('distance_from_')))
    df["color"] = df['closest'].map(lambda x: colmap[x])
    return df


def update(df, centroids):
    # 更新K个类别的中心点
    for i in centroids.keys():
        # 每个类别的中心点为 属于该类别的点的x、y坐标的平均值
        centroids[i][0] = np.mean(df[df['closest'] == i]['x'])
        centroids[i][1] = np.mean(df[df['closest'] == i]['y'])
    return centroids


def main():
    df = pd.DataFrame({
        'x': [12, 20, 28, 18, 10, 29, 33, 24, 45, 45, 52, 51, 52, 55, 53, 55, 61, 64, 69, 72, 23],
        'y': [39, 36, 30, 52, 54, 20, 46, 55, 59, 63, 70, 66, 63, 58, 23, 14, 8, 19, 7, 24, 77]
    })
    k = 3
    colomap = {0: "r", 1: "g", 2: "b"}
    first_center_index = random.randint(0, len(df) - 1)
    first_center = [df['x'][first_center_index], df['y'][first_center_index]]
    center = select_center(first_center, df, k, colomap)

    df = assignment(df, center, colomap)

    for i in range(10):  # 迭代10次
        closest_center = df['closest'].copy(deep=True)
        center = update(df, center)  # 更新K个类的中心点
        df = assignment(df, center, colomap)  # 类别中心点更新后,重新计算所有样本点到K个类别中心点的距离
        if closest_center.equals(df['closest']):  # 若各个样本点对应的聚类类别不再变化,则结束聚类
            break

    plt.scatter(df['x'], df['y'], color=df['color'], alpha=0.5, edgecolor='b')
    for j in center.keys():
        plt.scatter(*center[j], color=colomap[j], linewidths=6)
    plt.xlim(0, 80)
    plt.ylim(0, 80)
    plt.show()


if __name__ == '__main__':
    main()

实现效果:


3.4优缺点

优点:

  • 避免了Kmeans随机选取k个聚类中心导致可能聚类中心选择的不好,最终对结果会产生很大的影响的问题
  • 在目标检测应用中,Kmeans++通过改变初始聚类中心的生成方式,增大初始锚框之间差距,使锚框更适应整体据分布,得到了匹配度更好的多尺度锚框,进而提升了模型的检测性能。

 缺点:

  • 由于聚类中心点选择过程中的内在有序性,在扩展方面存在着性能方面的问题(第k个聚类中心点的选择依赖前k-1个聚类中心点的值)。

 

 本文参考:

全面解析Kmeans聚类算法(Python)

机器学习 K-Means(++)算法

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1 分钟给 Siri 升个级!从智Z变身 ChatSiri!

原文链接:https://forum.laf.run/d/79/17 众所周知,Siri 是一个智 Z!那么如果能接入大火的 chatGPT,是不是就会从智 Z 变成人工智能?! 众所周知,Laf 是一个集函数、数据库、存储为一体的云开发…

opencv-LSD线特征库文件

OpenCv-LSD线特征库使用 下载线特征库文件在工程源码中引入线特征头文件 下载线特征库文件 下面是阿里云盘链接 https://www.aliyundrive.com/s/rPxrmusTNPM 我们需要删掉build文件夹,并重新创建build文件夹。 并在build文件夹打开终端执行以下命令: …

Redis高可用之哨兵挂了,主从库还能切换吗

通过部署多个实例,就形成了一个哨兵集群,哨兵集群中的多个实例共同判断,可以降低对主库下线的误判率。 考虑一个问题:如果有哨兵实例在运行时发生了故障,主从库还能正常切换吗? 实际上,一旦多…

【Java 数据结构】二叉树的经典面试题 (图解)

🎉🎉🎉点进来你就是我的人了 博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔🦾&am…

【力扣-206】反转链表

🖊作者 : Djx_hmbb 📘专栏 : 数据结构 😆今日分享 : ----------“覆蕉寻鹿”: 有的人把假的当成真的,而又有人把明明是真的事情当成假的,前者可以说是“黄粱美梦”,后面这种就是“覆蕉寻鹿”。以前有个樵夫…

清理C盘的几种方法,帮你解决C盘爆红的烦恼

目录 C盘空间不足的原因: 清理方法 一、利用Windows自己附带的磁盘清理工具 二、存储设置清理 三、开启自动清理 四、将系统文件夹进行转移 五、清理系统缓存 六、利用清理软件进行清理 C盘空间不足的原因: 我们使用电脑时,c盘总是不知不觉…

K_A32_002 基于STM32等单片机驱动红外接收模块 串口+OLED0.96显示

K_A32_002 基于STM32等单片机驱动红外接收模块 串口OLED0.96显示 所有资源导航一、资源说明二、基本参数参数引脚说明 三、驱动说明时序:对应程序: 四、部分代码说明1、接线引脚定义1.1、STC89C52RC红外接收模块1.2、STM32F103C8T6红外接收模块 五、基础知识学习与相关资料下载…

软件测试工程师四大项目实战,再也不怕简历没项目写了

目录 1、宠明app 测试工程师 个人职责 2、薪时贷 测试工程师 个人职责 3、花花直播 测前端开房间内软件 个人职责 4、全本小说app 测试工程师 个人职责 5、总结 1、宠明app 测试工程师 宠明APP由APP用户前端和Web后台管理端组成。前端面向用户提供多功能宠物生活管理&am…

卷积神经网络分类算法的模型训练

模型训练 卷积神经网络分类算法的模型训练模型创建与编译模型训练及保存模型保存模型生成图像预处理 卷积神经网络分类算法的模型训练 启动Web服务器、应用使用说明和测试结果示例。 模型创建与编译 原VGG-16模型要求输入2242243的图片,限于GPU的计算能力&#x…

在线题库整理及一些刷题注意事项

在线题库整理及一些刷题注意事项 刷题站CSDN编程语言支持 LeetCode编程语言支持数据库语言支持 牛客网编程语言支持数据库语言支持 洛谷编程语言支持 AcWing编程语言支持 蓝桥编程语言支持 做题的两种模式调用模式委托模式 注意事项小结 刷题站 老顾一个人单打独斗太久了&…

ch05-学习率调整策略、可视化与Hook

ch05-学习率调整策略、可视化与Hook 0.引言1.学习率调整策略1.1.为什么要调整学习率?1.2.Pytorch提供的六种学习率调整策略1.3.学习率调整策略总结 2.TensorBoard 介绍1.1.SummaryWriter1.2.add_scalar1.3.add_scalars1.4.add_histogram1.5.模型指标监控1.6.add_ima…

Node【八】Express框架【二】

文章目录 🌟前言🌟中间件🌟中间件函数🌟什么是中间件函数🌟中间件函数可以做什么 🌟Express中间件的类型🌟应用级中间件🌟路由器级中间件🌟错误处理中间件🌟内…

Pycharm设置.py文件模版和设置活动模版(代码自动补全)

一、设置.py文件模版 有时候我们想新建.py文件的时候,让这个文件里面默认有一些内容,比如utf-8编码修改,我们应该怎么在PyCharm中设置呢? 依次点击 File -> Settings -> Editor -> File and Code Template,进…

基于亚马逊云科技无服务器架构,开发者可以有效实现快速上线

开发一个“爆款”游戏总共需要几步?Marvel Snap可能会告诉你:第一步,专心致志把游戏做好、提高可玩性;第二步,把其他工作交给亚马逊云科技。 相关数据显示,自2022年10月18日正式发行以来,在不到…

Vue 条件语句

文章目录 Vue 条件语句条件判断v-ifv-elsev-else-ifv-show Vue 条件语句 条件判断 v-if 条件判断使用 v-if 指令&#xff1a; v-if 指令 在元素 和 template 中使用 v-if 指令&#xff1a; <div id"app"><p v-if"seen">现在你看到我了<…

Stereo-Detection:适合新手的双目测距开源项目

简介&#xff1a;Stereo-Detection 是一个传统的SGBM深度测距yolov5目标检测&#xff0c;并部署在Jeston nano的开源教程。它致力于让更多的大四学生毕业&#xff0c;以及让研一学生入门 开源链接&#xff1a;yzfzzz/Stereo-Detection: Conventional SGBM depth ranging yolov…

重要公告 | 关于88号公投和近期Moonbeam区块生产中断的根本原因分析

2023年4月5日&#xff0c;Moonbeam网络经历了短暂的区块生产暂停问题&#xff0c;这是已批准的88号公投带来的意外结果。该问题源于链上公投的批准结果先于runtime升级发布&#xff0c;然而对这次公投的调用顺序却被安排在了runtime升级之后的区块。本文提供了对该事件的详细事…

16、CycriptLogos

一、Cycript Cycript是由Cydia创始人Saurik推出的一款脚本语言,Cycript混合了OC、JavaScript语法的解释器,这意味着我们能够在一个命令中使用OC或者JavaScript,甚至两者并用.它能够挂钩正在运行的进程,能够在运行时修改很多东西. 官网下载/ MonkeyDev自动配置下载是一种脚本语…

浅析EasyCVR平台基于B/S架构的技术特点与应用

EasyCVR基于云边端协同&#xff0c;可支持海量视频的轻量化接入与汇聚管理。平台兼容性强、拓展度高&#xff0c;可提供视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联等功能。 EasyCVR视频融合平台采用…

手把手教你针对层级时间轮(TimingWheel)延时队列的实战落地

承接上文 承接上文&#xff0c;让我们基本上已经知道了「时间轮算法」原理和核心算法机制&#xff0c;接下来我们需要面向于实战开发以及落地角度进行分析如何实现时间轮的算法机制体系。 前言回顾 什么是时间轮 调度模型&#xff1a;时间轮是为解决高效调度任务而产生的调…