k-means聚类算法k-means++聚类算法

news2024/9/22 5:35:28

k-means聚类算法&k-means++聚类算法


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

聚类算法的一般过程


  1. **数据准备:**包括特征标准化和降维;
  2. **特征选择:**从最初的特征中选择最有效的特征,并将其存储于向量中;
  3. **特征提取:**通过对所选择的特征进行转换形成新的突出特征;
  4. **聚类(或分组):**首先选择合适特征类型的某种距离函数(或构造新的距离函数)进行接近程度的度量,而后执行聚类或分组;
  5. **聚类结果评估:**是指对聚类结果进行评估,评估主要有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值会带来不同的结果,如下图所示:

image

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

2.3.1先验法

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

image

image

2.3.2手肘法

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

image

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()

实现效果:

image


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()

实现效果:

image


3.4优缺点

*优点:*

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

*缺点:*

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

附录

k-means++代码:http://rosettacode.org/wiki/K-means%2B%2B_clustering

参考文章:聚类算法:Kmeans和Kmeans++算法精讲-阿里云开发者社区 (aliyun.com)

*缺点:**

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

附录

k-means++代码:http://rosettacode.org/wiki/K-means%2B%2B_clustering

参考文章:聚类算法:Kmeans和Kmeans++算法精讲-阿里云开发者社区 (aliyun.com)

在这里插入图片描述

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

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

相关文章

从战略到系统架构:信息系统设计的全面解析

在当今数字化时代,信息系统已成为企业运营、管理和创新的核心驱动力。信息系统设计的重要性不仅关乎企业的技术实现,更直接影响到企业的战略执行和市场竞争能力。本文将从战略视角出发,深入探讨信息系统设计的全过程,包括从战略制…

使用Nexus搭建Maven私服仓库

一、私服仓库简介 在Java的世界中,我们通常使用Maven的依赖体系来管理构件(artifact,又称为二方库或三方库)的依赖,Maven仓库用于存储这些构件。一般的远程仓库(比如Maven Central)只提供下载功…

微信小程序中实现自动滚动

使用scroll-view组件的scroll-into-view属性&#xff1a; <scroll-view class"container" scroll-y"{{true}}" scroll-into-view"recordBottomScroll"><view class"text_style" style"color: #252526;">{{te…

Ubuntu20.04 源码安装 OMPL 与 Moveit

文章目录 一、源码安装OMPL1.1 先检查是否已安装二进制 ompl1.2 若已经提前安装二进制&#xff0c;需先行卸载1.3 OMPL官网安装教程 二、源码安装 moveit2.1 先检查是否已安装二进制Moveit2.2 源码安装 Moveit2.2.1、更新软件包2.2.2、安装依赖2.2.3、创建Moveit工作空间2.2.4…

8月12日学习笔记 DNS补充

一&#xff0c;DNS工作原理 查询方式 1.递归查询&#xff0c;逐级查询&#xff0c;一次到位&#xff0c;但是速度慢 2.迭代查询&#xff0c;多次查询一个地址&#xff0c;可以缓存 一次递归&#xff0c;多次迭代 dig解析域名 yum -y install bind-utils.x86_64 dig trace …

selenium使用Edge的 webdriver提示错误

最近由于项目的原因需要更换selenium的驱动&#xff0c;从Google谷歌更换成Edge驱动&#xff0c;然后发现官方下载的驱动文件不能直接放到python执行&#xff0c;提示一直在报错&#xff0c;后续通过多方查找才知道是驱动名称问题&#xff01;&#xff01;&#xff01; 查看Ed…

Hadoop-yarn-unauthorized 未授权访问漏洞

一、漏洞描述&#xff1a; Hadoop是一款由Apache基金会推出的分布式系统框架&#xff0c;它通过著名的 MapReduce 算法进行分布式处理&#xff0c;Yarn是Hadoop集群的资源管理系统。YARN提供有默认开放在8088和8090的REST API&#xff08;默认前者&#xff09;允许用户直接通过…

【网络】IP-VPN技术概述

目录 引言 核心协议 封装与加密 工作流程 IP-VPN的应用场景 MPLS-VPN 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 IP-VPN&#xff08;Internet Protocol - Virtual Private Network&#xff09;是一种通过公共网络实现私密、安全通信的技术。它主要依赖于互联网…

【LabVIEW学习篇 - 14】:信号量、集合点、事件发生

信号量 信号量技术是用来限制同时访问共享资源的数量。当访问量达到信号量设定的数量之后&#xff0c;其它任务只能等待&#xff0c;直到有任务释放访问权限。 比如打印机打印任务、银行办理业务时的叫号排队等等。 案例&#xff1a;使用信号量&#xff0c;实现两个波形图表轮…

在ubuntu、centos、openEuler安装Docker、构建一个简单的 Nginx 镜像

目录 ubuntu、centos、openEuler安装Docker 1.在 Ubuntu 上安装 Docker 1. 1 更新软件包 1. 2 安装必要的依赖 1.3 添加 Docker 的 GPG 密钥 1.4 添加 Docker 仓库 1.5 更新软件包 1.6 安装 Docker 1.7 启动并启用 Docker 服务 1.8 验证安装 1.9 运行测试容器 1.10…

【NXP-MCXA153】SPI驱动移植

介绍 SPI总线由摩托罗拉公司开发&#xff0c;是一种全双工同步串行总线&#xff0c;由四个IO口组成&#xff1a;CS、SCLK、MISO、MOSI&#xff1b;通常用于CPU和外设之间进行通信&#xff0c;常见的SPI总线设备有&#xff1a;TFT LCD、QSPI FLASH、时钟模块、IMU等&#xff1b…

假如萝卜快跑撞了人,谁来负责?

引言 自动驾驶时代来临&#xff0c;司机的身影消失。但没有了司机&#xff0c;交通事故谁来负责&#xff1f;在AI刚爆火时&#xff0c;有个半调侃的笑话很出名&#xff1a;AI肯定不能替代会计和律师&#xff0c;因为一旦出了事&#xff0c;AI负不了责&#xff0c;但会计和律师…

Nest.js 实战 (九):使用拦截器记录用户 CURD 操作日志

前言 有一天&#xff0c;公司的产品经理提了一个需求&#xff1a;系统需要记录每个用户的 CURD 操作&#xff0c;也就是说用户新增、编辑或者删除了什么数据&#xff0c;都需要记录下来&#xff0c;这个在 Nest.js 中如何实现呢&#xff1f; 这时候我们可以考虑使用 拦截器 来…

《书生大模型实战营第3期》进阶岛 第一关: 探索 InternLM 模型能力边界

文章大纲 OpenCompass 评测体验大模型对比评测 - Bad caseBad Case 1Bad Case 2Bad Case 3Bad Case 4Bad Case 5 大模型对比评测 - Good caseGood case 1Good Case 2 任务其他学习内容参考文献本人学习系列笔记第二期第三期 课程资源论文其他参考 OpenCompass 评测体验 https:…

opencv-python图像增强七:图像亮度对比度饱和度调整

文章目录 一&#xff0c;简介二&#xff0c;图像亮度对比度修改三&#xff0c;对比度增强&#xff1a; 一&#xff0c;简介 在图像处理领域&#xff0c;对比度、亮度和饱和度是影响图像视觉效果的重要因素。合理调整这三个参数&#xff0c;可以使图像更具表现力&#xff0c;满…

北斗短报文通信原理

短报文通信原理主要基于北斗卫星导航系统&#xff0c;其过程可以分为以下几个步骤&#xff1a;用户机将包含接收方ID号和通讯内容的通讯申请信号加密后通过卫星转发入站;地面中心站接收到通讯申请信号后&#xff0c;进行脱密和再加密处理&#xff0c;然后将其加入持续广播的出站…

WindowsAPI 查阅笔记:线程、多个线程互同步

1. 线程的创建 HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全属性 SIZE_T dwStackSize, //线程堆栈大小 LPTHREAD_START_ROUTINE lpStartAddress, //重要: 线程函数指针 LPVOID lpParameter, //重要: 启动线程函数 DWORD dwC…

分布式知识总结(一致性Hash算法)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 一致性Hash算法 假如有三台服务器编号node0、node1、node2&…

若依项目改造-sqlserver(2)

目前启动时&#xff0c;不需要配置数据库 1、启动时&#xff0c;不用检查数据库连接 2、可以在线导出数据库备份bak文件 3、实现不用配置jdk环境启动 4、实现启动没有控制台窗口