【Mo 人工智能技术博客】K-means:无监督聚类的经典算法

2023-11-03

K-means:无监督聚类的经典算法

作者:郑培

无监督学习是一类用于在数据中寻找模式的机器学习技术。无监督学习算法使用的输入数据都是没有标注过的,这意味着数据只给出了输入变量(自变量 X)而没有给出相应的输出变量(因变量)。在无监督学习中,算法本身将发掘数据中有趣的结构。在监督学习中,系统试图从之前给出的示例中学习。(而在无监督学习中,系统试图从给定的示例中直接找到模式。)因此,如果数据集被标注过了,这就是一个监督学习问题;而如果数据没有被标注过,这就是一个无监督学习问题。

聚类属于无监督学习,以往的回归、朴素贝叶斯、SVM等都是有类别标签y的,也就是说样例中已经给出了样例的分类。而聚类的样本中却没有给定y,只有特征x。K-means 是我们常用的基于欧式距离的聚类算法,它是数值的、非监督的、非确定的迭代的,该算法旨在最小化一个目标函数——误差平方函数(所有的观测点与其中心点的距离之和),其认为两个目标的距离越近,相似度越大,由于具有出色的速度和良好的可扩展性,Kmeans聚类算法算得上是著名的聚类方法。本文将带大家回顾K-means算法的理论内涵以及初始化优化K-Means++方法。

本文的项目实例实现在Momodel平台上,可以边看边学哦!
mo平台项目地址:https://momodel.cn/workspace/5eb7e4a31089644d6a4e5c4b?type=app

1 简介

直观了解K-means算法有许多有趣的例子,其中有一个著名的解释,即牧师—村民模型:

有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的村民,于是每个村民到离自己家最近的布道点去听课。听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的村民的地址,搬到了所有地址的中心地带,并且在海报上更新了自己的布道点的位置。牧师每一次移动不可能离所有人都更近,有的人发现A牧师移动以后自己还不如去B牧师处听课更近,于是每个村民又去了离自己最近的布道点…… 就这样,牧师每个礼拜更新自己的位置,村民根据自己的情况选择布道点,最终稳定了下来。

我们可以看到该牧师的目的是为了让每个村民到其最近中心点的距离和最小。在实际生活中,许多数据的聚类可以通过观察得出,但是如何让计算机找出聚类的点群就需要像K-means这类的算法帮助。
K-means目标
图一 K-means目标

在聚类问题中,给我们的训练样本是 $ \left{x^{(1)}, \ldots, x^{(m)}\right}, \quad x^{(i)} \in \mathbb{R}^{n} , K − m e a n s 算法是将样本聚类成 ,K-means算法是将样本聚类成 Kmeans算法是将样本聚类成k$个簇(cluster),具体算法描述如下:

  1. 随机选取 k k k个聚类质心点(cluster centroids)为 μ 1 , μ 2 , … , μ k ∈ R n \mu_{1}, \mu_{2}, \ldots, \mu_{k} \in \mathbb{R}^{n} μ1,μ2,,μkRn_
  2. 重复下面过程直到收敛:
    1. 对于每一个样例i,计算其应该属于的类: c ( i ) : = arg ⁡ min ⁡ j ∥ x ( i ) − μ j ∥ 2 c^{(i)}:=\arg \min _{j}\left\|x^{(i)}-\mu_{j}\right\|^{2} c(i):=argminj x(i)μj 2
    2. 对于每一个类j,重新计算该类的质心: μ j : = ∑ i = 1 m 1 { c ( i ) = j } x ( i ) ∑ i = 1 m 1 { c ( i ) = j } \mu_{j}:=\frac{\sum_{i=1}^{m} 1\left\{c^{(i)}=j\right\} x^{(i)}}{\sum_{i=1}^{m} 1\left\{c^{(i)}=j\right\}} μj:=i=1m1{c(i)=j}i=1m1{c(i)=j}x(i)

K是我们事先给定的聚类数, c ( i ) c^{(i)} c(i) 距离最近的那个类, c ( i ) c^{(i)} c(i)的值是1到k中的一个。质心 μ j \mu_{j} μj 代表我们对属于同一个类的样本中心点的猜测,拿星团模型来解释就是要将所有的星星聚成k个星团,首先随机选取k个宇宙中的点(或者k个星星)作为k个星团的质心,然后第一步对于每一个星星计算其到k个质心中每一个的距离,然后选取距离最近的那个星团作为 c ( i ) c^{(i)} c(i),这样经过第一步每一个星星都有了所属的星团;第二步对于每一个星团,重新计算它的质心 μ j \mu_{j} μj(对里面所有的星星坐标求平均)。重复迭代第一步和第二步直到质心不变或者变化很小。

下图展示了对n个样本点进行K-means聚类的效果,这里k取2。

K-means面对的第一个问题是如何保证收敛,前面的算法中强调结束条件就是收敛,可以证明的是K-means完全可以保证收敛性。下面我们定性的描述一下收敛性,我们定义畸变函数(distortion function)如下:
J ( c , μ ) = ∑ i = 1 m ∥ x ( i ) − μ c ( i ) ∥ 2 J(c, \mu)=\sum_{i=1}^{m}\left\|x^{(i)}-\mu_{c^{(i)}}\right\|^{2} J(c,μ)=i=1m x(i)μc(i) 2

J J J函数表示每个样本点到其质心的距离平方和。K-means是要将J调整到最小。假设当前J没有达到最小值,那么首先可以固定每个类的质心 μ j \mu_{j} μj,调整每个样例的所属的类别 c ( i ) c^{(i)} c(i) 来让J函数减少。同样,固定 c ( i ) c^{(i)} c(i),调整每个类的质心 μ j \mu_{j} μj也可以使J减小。这两个过程就是内循环中使J单调递减的过程。当J递减到最小时, μ \mu μ c c c也同时收敛。(在理论上,可以有多组不同的 μ \mu μ c c c值能够使得J取得最小值,但这种现象实际上很少见)。

由于畸变函数J是非凸函数,意味着我们不能保证取得的最小值是全局最小值,也就是说k-means对质心初始位置的选取比较感冒,但一般情况下k-means达到的局部最优已经满足需求。但如果你怕陷入局部最优,那么可以选取不同的初始值跑多遍k-means,然后取其中最小的J对应的 μ \mu μ c c c输出。

2 K-means 细节与调优

K-means 算法具有很多优点,例如:聚类效果良好,局部最优在很多情况能够满足需求;在处理大数据集时,可以保证较好的伸缩性;算法复杂度低;当簇近似高斯分布的时候,效果优良。但是K-Means主要有两个最重大的缺陷——都和初始值有关:

  1. K 是事先给定的,这个 K 值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。
  2. K-Means算法需要用初始随机种子点来计算,这个随机种子点太重要,不同的随机种子点会有得到完全不同的结果。

2.1 K值选取

K 值的选取对 K-means 影响很大,这也是 K-means 最大的缺点,常见的选取 K 值的方法有:手肘法、Gap statistic 方法。
如果我们拿到的样本,客观存在J个“自然小类”,这些真实存在的小类是隐藏于数据中的。三维以下的数据我们还能画图肉眼分辨一下J的大概数目,更高维的就不能直观地看到了,我们只能从一个比较小的K,譬如K=2开始尝试,去逼近这个真实值 J J J

  • 当K小于样本真实簇数J时,K每增大一个单位,就会大幅增加每个簇的聚合程度,这时距离和的下降幅度会很大;
  • 当K接近J时,再增加K所得到的聚合程度回报会迅速变小,距离和的下降幅度也会减小;
  • 随着K的继续增大,距离和的变化会趋于平缓。

例如下图,真实的J我们事先不知道,那么从K=2开始尝试,发现K=3时,距离和大幅下降,K=4时,下降幅度急速缩水,再后面就越来越平缓。所以我们认为J应该为3,因此可以将K设定为3。

手肘法的缺点在于需要人工看不够自动化,所以我们又有了 Gap statistic 方法,这个方法出自斯坦福大学的几个学者的论文:Estimating the number of clusters in a data set via the gap statistic, 对应公式如下:

Gap ⁡ ( K ) = E ( log ⁡ D k ) − log ⁡ D k \operatorname{Gap}(K)=\mathrm{E}\left(\log D_{k}\right)-\log D_{k} Gap(K)=E(logDk)logDk

其中 D k D_{k} Dk 为损失函数,这里 E ( log ⁡ D k ) E\left(\log D_{k}\right) E(logDk) 指的是 log ⁡ D k \log D_{k} logDk 的期望。这个数值通常通过蒙特卡洛模拟产生,我们在样本里所在的区域中按照均匀分布随机产生和原始样本数一样多的随机样本,并对这个随机样本做 K-Means,从而得到一个 D k D_{k} Dk。如此往复多次,通常 20 次,我们可以得到 20 个 log ⁡ D k \log D_{k} logDk。对这 20 个数值求平均值,就得到了 E ( log ⁡ D k ) E\left(\log D_{k}\right) E(logDk) 的近似值。最终可以计算 Gap Statisitc。而 Gap statistic 取得最大值所对应的 K 就是最佳的 K。

由图可见,当 K=3 时,Gap(K) 取值最大,所以最佳的簇数是 K=3。

2.2 K-means++

在上文中我们提到,k个初始化的质心的位置选择对最后的聚类结果和运行时间都有很大的影响,因此需要选择合适的k个质心。如果仅仅是完全随机的选择,有可能导致算法收敛很慢。K-Means++算法就是对K-Means随机初始化质心的方法的优化。K-Means++的对于初始化质心的优化策略也很简单,如下:

  1. 从输入的数据点集合中随机选择一个点作为第一个聚类中心 μ 1 μ_1 μ1
  2. 对于数据集中的每一个点 x i x_i xi,计算它与已选择的聚类中心中最近聚类中心的距离: D ( X i ) = a r g    m i n ∣ ∣ x i − μ r ∣ ∣ 2 2 r = 1 , 2 … … k s e l e c t e d D(X_i)=arg\; min||x_i-μ_r||^2_2 \qquad r=1,2……k_selected D(Xi)=argmin∣∣xiμr22r=1,2……kselected
  3. 选择一个新的数据点作为新的聚类中心,选择的原则是: D ( x ) D(x) D(x)较大的点,被选取作为聚类中心的概率较大
  4. 重复2和3直到选择出k个聚类质心
  5. 利用这k个质心来作为初始化质心去运行标准的K-Means算法
    简单的来说,就是 K-means++ 就是选择离已选中心点最远的点。这也比较符合常理,聚类中心当然是互相离得越远越好。

3 K-means算法应用

看到这里,你会说,K-Means算法看来很简单,而且好像就是在玩坐标点,没什么真实用处。而且,这个算法缺陷很多,还不如人工呢。是的,前面的例子只是玩二维坐标点,的确没什么意思。但是你想一下下面的几个问题:

  1. 不是二维的,是多维的,如5维的,那么,就只能用计算机来计算了。
  2. 坐标点的X, Y 坐标,其实是一种向量,是一种数学抽象。现实世界中很多属性是可以抽象成向量的,比如,我们的年龄,我们的喜好,我们的商品,等等,能抽象成向量的目的就是可以让计算机知道某两个属性间的距离。如:我们认为,18岁的人离24岁的人的距离要比离12岁的距离要近,鞋子这个商品离衣服这个商品的距离要比电脑要近,等等。只要能把现实世界的物体的属性抽象成向量,就可以用K-Means算法来归类了

mo平台项目地址:https://momodel.cn/workspace/5eb7e4a31089644d6a4e5c4b?type=app

参考文献:

[1]https://ww2.mathworks.cn/help/stats/kmeans.html
[2]https://en.wikipedia.org/wiki/K-means%2B%2B
[3]https://github.com/Anfany/Machine-Learning-for-Beginner-by-Python3/tree/master/Kmeans%20Cluster

关于我们

Mo(网址:https://momodel.cn) 是一个支持 Python的人工智能在线建模平台,能帮助你快速开发、训练并部署模型。

近期 Mo 也在持续进行机器学习相关的入门课程和论文分享活动,欢迎大家关注我们的公众号 MomodelAI 获取新资讯!

同时,欢迎使用 「Mo AI编程」 微信小程序

以及登录官网,了解更多信息:Mo 平台

Mo,发现意外,创造可能

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Mo 人工智能技术博客】K-means:无监督聚类的经典算法 的相关文章

  • Python Tweepy:Twitter Api 说 /users/lookup 不存在

    我正在制作一个研究应用程序 研究具有高权威的 Twitter 用户之间的交互 其中一部分是提取有关用户的信息 我使用 Tweepy for Python 构建了一个应用程序 过去 2 天我一直在提取用户信息 没有出现任何问题 突然提出这样的
  • 按 A 列删除重复项,保留 B 列中具有最高值的行

    我有一个数据框 A 列中有重复值 我想删除重复项 保留 B 列中具有最高值的行 So this A B 1 10 1 20 2 30 2 40 3 10 应该变成这样 A B 1 20 2 40 3 10 我猜想可能有一种简单的方法可以做到
  • 在 python 中查找价格动量的有效方法:对列的最后 n 个条目求平均值

    我正在定义价格动量是给定股票过去动量的平均值n days 反过来 动量是一种分类 如果当天的收盘价高于前一天 则每天标记为 1 如果当天的收盘价低于前一天 则标记为 1 我的库存变化百分比如下 df close in percent np
  • Selenium 上的切换窗口

    我在 Python 中使用 Selenium 和 PhantomJS 我需要打开一个新窗口并控制它 出于测试目的 我这样做 from selenium import webdriver driver webdriver PhantomJS
  • 带有redirect_uri的social-auth-app-django Facebook后端状态

    我知道我的问题听起来像是重复的 但我到处寻找但没有找到任何解决方案 我正在努力为我的 django web 应用程序实现社交登录 到目前为止 谷歌 推特和雅虎登录均按预期工作 但facebook总是给出以下错误 URL 被阻止 此重定向失败
  • 有效地写入 pandas 中的多个相邻列

    使用 numpy ndarray 可以一次写入多个列 而无需先进行复制 只要它们相邻 如果我想写入数组的前三列 我会写 a 0 0 3 1 2 3 this is very fast a is a numpy ndarray 我希望在 pa
  • 如何在 iPython 中获取最后分配的变量的值?

    我是一个完全的 iPython 新手 但我想知道是否有办法获取最后分配的变量的值 In 1 long variable name 333 In 2
  • 更新或插入 MySQL Python

    如果记录已存在 我需要更新一行 如果不存在 我需要创建一个新记录 我理解 ON DUPLICATE KEY 将使用 MYSQLdb 完成此操作 但是我无法使其正常工作 我的代码如下 cursor database cursor cursor
  • Tkinter:通过多处理启动进程会创建不需要的新窗口

    我计划围绕数值模拟编写一个小型 GUI 这就是我现在使用 Tkinter 的原因 模拟应在单独的进程中从 GUI 启动 为了玩一下 我定义了一个函数 random process 来生成成对的 randn 数字 这应该是一个真正的模拟过程
  • 创建 df 以生成给定格式的 json

    我正在尝试生成一个 df 来生成下面的 json Json数据 name flare children name K1 children name Exact size 4 name synonyms size 14 name K2 chi
  • 如何避免在matplotlib中调用latex(输出到pgf)

    我使用 matplotlib 及其 pgf 后端来生成包含在 LaTeX 投影仪文档中的绘图 当我使用未定义的乳胶命令时 我遇到了麻烦 但对于我的应用程序 我不需要 matplotlib 来使用 Latex 生成标签或注释 我只想要正确的
  • 我无法设置顶级标题

    我想为 TopLevel 设置标题 但 TopLevel 显示 Root 的标题 我认为我的下一个脚本与 TkInter 文档中的示例相对应 但给了我不好的结果 你能解释一下 为什么我的设置master title 顶部 in 应用程序顶部
  • 如何在 PyTorch 中对子集使用不同的数据增强

    如何针对不同的情况使用不同的数据增强 转换 Subset在 PyTorch 中吗 例如 train test torch utils data random split dataset 80000 2000 train and test将具
  • 在 grpc python 中处理异步流请求

    我试图了解如何使用双向流处理 grpc api 使用 Python API 假设我有以下简单的服务器定义 syntax proto3 package simple service TestService rpc Translate stre
  • 检测反射 DLL 注入

    在过去的几年中 恶意软件 以及一些渗透测试工具 如 Metasploit 的 meterpreter 负载 已经开始使用反射 DLL 注入 PDF http www harmonysecurity com files HS P005 Ref
  • Google App Engine self.redirect() POST 方法

    在 GAE Python 中 使用 webApp 框架 调用 self redirect some url 通过 GET 方法将用户重定向到该 URL 是否也可以通过带有一些参数的 POST 方法进行 重定向 如果可以的话 怎样做 Than
  • 访问 Scrapy 内的 django 模型

    是否可以在 Scrapy 管道内访问我的 django 模型 以便我可以将抓取的数据直接保存到我的模型中 我见过this https scrapy readthedocs org en latest topics djangoitem ht
  • 使用 pyspark 计算所有可能的单词对

    我有一个文本文档 我需要找到整个文档中重复单词对的可能数量 例如 我有下面的word文档 该文档有两行 每行用 分隔 文档 My name is Sam My name is Sam My name is Sam My name is Sa
  • *Python 内的 Kaggle API 文档?

    我想写一个python从 Kaggle com 下载公共数据集的脚本 Kaggle API 是用 python 编写的 但是我能找到的几乎所有文档和资源都是关于如何在命令行中使用该 API 的 而关于如何使用kaggle图书馆内python
  • Pandas:如何删除以 nan 作为列名的多个列?

    根据标题 这是一个可重现的示例 raw data x this that this that this np nan np nan np nan np nan np nan np nan y np nan np nan np nan np

随机推荐

  • nginx前后端分离部署无法访问到后端接口

    先看一组错误案例 user nobody worker processes 1 error log logs error log error log logs error log notice error log logs error lo
  • 【程序运行时的两种环境】

    目录 前言 一 翻译环境 一 预编译 二 编译 三 汇编 四 链接 二 执行环境 三 补充 总结 前言 在ANSI C的任何一种实现中 都要经过两种环境 一种是编译环境 用于将程序代码转换为可执行的机器指令 二进制指令 另一种是执行环境 用
  • 【C++】细说C++中的数组之动态数组

    转载自如下位置 https blog csdn net u013921430 article details 79514972 以备学习
  • 前端引入和html标签

    先安装 flask模块 pip install flask from flask import Flask app Flask name 创建了网址 show info 和函数index的对应关系 以后用户在浏览器上访问 show info
  • 前端小程序面试题(一)

    首先说一些为什么总结小程序相关的面试题吧 我们可以随便打开一个招聘网站 在那里你会发现市场对于小程序的需求还是蛮高的 有些公司可能就只需要写小程序的前端人员 虽然小程序的开发很大一部分都是很简单的 但是有些常用的东西还是有必要了解一下的 故
  • Android代码实现APK文件的安装与卸载

    Android程序使用代码的安装和卸载 安装 String str CanavaCancel apk String fileName Environment getExternalStorageDirectory str Intent in
  • Zebra-VTYSH源码分析和改造(二):深入代码

    分析Zebra VTYSH的源码 首先从main函数开始 在ztysh main c中找到main函数 来进一步分析流程执行如下图所示 在平时的使用中我们会发现 配置的时候有很多的视图 View 每个视图中有不同的命令可供用户输入进行配置
  • STM32—Flash读写详解

    目录 前言 介绍 STM32 FLASH 闪存的编程和擦除 Flash读写的标准库函数 软件设计 FLASH的读取 直接读取某一地址的内容 读取选定位置的选定大小的内容 FLASH的写入 直接使用标准库写入 写入选定位置的选定大小的内容 如
  • mega328p-ADC,PWM,UART驱动

    ADC驱动 函 数 名 Ai Init 函数功能 Ai端口初始化 输入参数 void 输出参数 void 返 回 值 void 参考文档 void 创 件 人 程强刚 创建日期 2016 02 09 修改历史 void Ai Init vo
  • 身份认证之多因素身份认证(MFA)

    我们大多数人都同意密码是不安全的身份验证形式这一观点 更糟糕的是 它完全不智能 但这引发了一个问题 如果密码不是解决安全问题的答案 那什么是 目前 答案可能是多因素身份验证 MFA 多因素身份验证增加了一层关键的防御 MFA使用两个或多个因
  • Filter过滤器完成验证代码的封装

    Filter过滤器完成验证代码的封装 filter是什么 1 使用filter 2 filter配置到项目中 验证用户权限是需要反复使用的代码块 把他封装到filter中 减少代码冗余 filter是什么 init 方法 初始化方法 在创建
  • 主板上还剩啥?CPU整合GPU/北桥/南桥

    泡泡网主板频道2月6日 众所周知 主板上最重要 成本最高的两颗芯片 被称为北桥和南桥 其中北桥负责与处理器对接 主要功能包括 内存控制器 PCI E控制器 集成显卡 前 后端总线等 都是速度较快的模块 而南桥则负责外围周边功能 速度较慢 主
  • c++ 读写excel_每天10分钟,轻松入门python,json、csv等读写

    JSON的全称是 JavaScript Object Notation 意思是JavaScript对象表示法 它是一种基于文本 独立于语言的轻量级数据交换格式 这种数据在弄爬虫的时候 经常会见到这类型的数据 下面展示一个简单的json数据
  • 利用计数器实现任意分频,占空比为60%(任意占空比)电路 [VHDL]

    本次实验为利用计数器实现分频常数为24000 占空比为60 的电路 也可以设置为任意分频 任意占空比的电路 一 设计思路 设计分析 要将原来的占空比为50 大频率的信号重新设为60 占空比 频率较小的周期信号 其中频率的思想就是分频器 利用
  • Northstar软件下载 以及搭建机器人时遇到的坑

    上个学期学机器人的时候 老师让我们用 innostar 创意之星 做出一个机器人来 但我翻遍全网也没找到创意之星的配套软件 我找了三天也没找到 公司官网也没有 给博创的人发邮件也不回 给我整的心态爆炸 为了方便后来的学弟学妹们 现在把我找到
  • Java 优先队列(PriorityQueue)总结

    PriorityQueue 实现的是 Queue 接口 可以使用 Queue 提供的方法 以及自带的方法 1 PriorityQueue概述 Java PriorityQueue 实现了 Queue 接口 不允许放入 null 元素 其通过
  • LVGL学习笔记

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 硬件要求 二 移植 1 准备工作 2 文件准备 3 加入工程 前言 LVGL 轻巧而多功能的图形库 是一个免费的开放源代码图形库 它提供创建具有易于使用的
  • Shopify Liquid 日期

    Shopify Liquid 日期变量 assign start date now date s assign start date year now date Y assign yoy start start date year minu
  • 基于卷积神经网络的车道线检测

    在本博客中 我们将探讨如何使用卷积神经网络 CNN 在Udacity自动驾驶数据集上进行车道线检测 我们将首先简要介绍自动驾驶的相关知识 然后介绍车道线检测的重要性 接下来 我们将构建一个CNN模型 并在Udacity数据集上对其进行训练和
  • 【Mo 人工智能技术博客】K-means:无监督聚类的经典算法

    K means 无监督聚类的经典算法 作者 郑培 无监督学习是一类用于在数据中寻找模式的机器学习技术 无监督学习算法使用的输入数据都是没有标注过的 这意味着数据只给出了输入变量 自变量 X 而没有给出相应的输出变量 因变量 在无监督学习中