k-means聚类算法从入门到精通

article/2025/10/1 15:48:58

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

k-means算法是非监督聚类最常用的一种方法,因其算法简单和很好的适用于大样本数据,广泛应用于不同领域,本文详细总结了k-means聚类算法原理 。

目录

1. k-means聚类算法原理

2. k-means聚类算法步骤

3. k-means++聚类优化算法

4. 小批量处理的k-means聚类算法

5. k值的选取

6. k-means聚类算法不适用的几个场景

7. k-means与knn区别

8. 小结

1. k-means聚类算法原理

聚类算法性能度量的文章提到若簇类相似度好簇间的相似度差,则聚类算法的性能较好。我们基于此定义k-means聚类算法的目标函数:

fe6bf285ce31bbfbddd1359d865c67a8.png 

其中422d553d77a3ff4a12645790c8737b40.png表示当样本dd5124455c0af613695051ca15b592ea.png划分为簇类k时为1,否则为0。

b1e44287315ad37330abfd9987aae506.png

c44ed63b5dbfd39a79bc5d77ff1a1cba.png表示簇类k的均值向量。

目标函数(1.1)在一定程度上刻画了簇内样本围绕簇均值向量的紧密程度,J值越小则簇内样本相似度越高。最小化目标函数是一个NP难题,k-means聚类运用EM算法思想实现模型的最优化。

1)初始化K个簇的均值向量,即476d7a0de7393cff5b4280c8bc3947c2.png是常数,求J最小化时的13c82e01368c33df30a84c8a624d54a9.png。我们不难知道当数据点划分到离该数据点最近的簇类时,目标函数J取最小。

2)已知083f70002ddf06af202c418573175159.png,求最小化J时相应的f521c3f4257c6bfea0c1a629101a90ce.png。令目标函数J对6be5a48d41fcea292a05fd22a7116001.png的偏导数等于0:

ac1024fad7a214ff62a0e3387deafb83.png

得:

5c7b1e58a073add3990672f5182ca0ea.png

80d93d66455dfe12831c6e20a77d0266.png表达式的含义是簇类中心等于所属簇类样本的均值。

本节用EM算法思想解释了k-means聚类算法的参数更新过程,相信大家对k-means聚类算法有一个更清晰的认识。

2. k-means聚类算法步骤

k-means聚类算法步骤实质是EM算法的模型优化过程,具体步骤如下:

1)随机选择k个样本作为初始簇类的均值向量;

2)将每个样本数据集划分离它距离最近的簇;

3)根据每个样本所属的簇,更新簇类的均值向量;

4)重复(2)(3)步,当达到设置的迭代次数或簇类的均值向量不再改变时,模型构建完成,输出聚类算法结果。

3. k-means++聚类优化算法

若给定足够的迭代次数,k-means算法就能收敛,但是有可能在局部最小值点收敛。k-means收敛局部极值的原因很可能是初始化簇类中心的距离很接近,而且算法的收敛时间也加长了,为了避免这一情况,多次运行k-means聚类算法,每次运行初始化不同的簇类中心。

另一种解决k-means收敛局部极值的方法是k++聚类算法,k-means++通过让簇间中心互相远离的方案来初始化簇类中心。

具体算法步骤:

1)随机选择一个样本数据作为第一个簇类中心711a142322290be163d308efc87ee4b4.png

2)计算每一个样本cb95dad1c3a55c454a8b15cccf8d6083.png到簇类中心2a1b1a0c12eb9e813664da0b4043b667.png的最小距离;

3a5b9d7c7e3371762ee6221a93123a51.png

3)选择最大距离的样本点作为簇类中心;

4)重复(2)(3),直到达到簇类个数k;

5)利用这k个簇类中心作为初始化的簇类中心运行k-means算法;

4. 小批量处理的k-means聚类算法

k-means聚类算法的时间复杂度随着样本数的增加而增大,若样本量达到上万时,k-means聚类算法非常耗时,因此对该数据集进行无放回随机抽样得到合适的小批量样本数据集,sklearn.cluster包提供了相应的实现方法MiniBatchKMeans。

小批量处理的k-means聚类算法在减少了收敛时间的同时,算法结果相差不大。如下结果用inertia评价k-means和MiniBatchKmeans的算法结果。

import timeimport numpy as np
import matplotlib.pyplot as pltfrom sklearn.cluster import MiniBatchKMeans, KMeans
from sklearn.metrics.pairwise import pairwise_distances_argmin
from sklearn.datasets.samples_generator import make_blobs# Generate sample data
np.random.seed(0)
# minibatch随机抽样100例样本进行训练
batch_size = 100
centers = [[1, 1], [-1, -1], [1, -1]]
n_clusters = len(centers)
# 产生3个簇类的30000个样本数据
X, labels_true = make_blobs(n_samples=30000, centers=centers, cluster_std=0.7)# k-means++算法
k_means = KMeans(init='k-means++', n_clusters=3, n_init=10)
t0 = time.time()
k_means.fit(X)
t_batch = time.time() - t0
# MiniBatchKMeans算法
mbk = MiniBatchKMeans(init='k-means++', n_clusters=3, batch_size=batch_size,n_init=10, max_no_improvement=10, verbose=0)
t0 = time.time()
mbk.fit(X)
t_mini_batch = time.time() - t0# 打印k-means++运行时间和性能度量
print("k-means++_runtime= ",t_batch)
print("k_means++_metics= ",k_means.inertia_)
# 打印minibatch_k_means++运行时间和性能度量值
print("MiniBatch_k_means++_runtime= ",t_mini_batch)
print("k_means_metics= ",mbk.inertia_)#>
k-means++_runtime=  0.36002039909362793
k_means++_metics=  25164.97821695812
MiniBatch_k_means++_runtime=  0.15800929069519043
k_means_metics=  25178.611517320118

图形结果表示:

b1b78975b1e3e8e42a1e3b09f1ca92c5.jpeg

5. 簇类个数k的选取

我们运用Calinski-Harabasz分数作为评价聚类性能的标准,分数越大,聚类性能越好,Calinski-Harabasz的含义请参考该文,

我们首先构建四个不同标准差的二维样本数据:

from sklearn import metrics
# 定义四个簇类中心
centers1 = [[0,0],[1, 1],[1.9, 2],[3, 3]]
# 定义每个簇类的标准差
std1 = [0.19,0.2,0.3,0.4]
# 算法可重复性
seed1 =45
# 产生4个簇类的30000个样本数据
X, labels_true = make_blobs(n_samples=30000, centers=centers1, cluster_std=std1,random_state=seed1)
plt.scatter(X[:,0],X[:,1],marker='o')
plt.show()

数据散点图如下:

e0f89fb2cc7aee95eb52312a381028c8.png

首先选择簇类个数为2,即K=2,查看聚类效果图和Calinski-Harabasz分数。

# 若我们选择k=2
k_means = KMeans(init='k-means++', n_clusters=2, n_init=10,random_state=10)
y_pred = k_means.fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
scores2 = metrics.calinski_harabaz_score(X,y_pred)
print("the Calinski-Harabasz scores(k=2) is: ",scores2)

散点图效果:

ddad86f3e1a298cf218c710c97211770.png

Calinski-Harabasz分数:

#> the Calinski-Harabasz scores(k=2) is:  85059.39875951338

选择簇类个数为3,即K=3,查看聚类效果图和Calinski-Harabasz分数。

散点图效果:

625c9050d31a4cec5f9e082bc8cd2bdb.png

Calinski-Harabasz分数:

#> the Calinski-Harabasz scores(k=3) is:  92778.08155077342

选择簇类个数为4,即K=4,查看聚类效果图和Calinski-Harabasz分数。

散点图效果:

5e3e882a13439e847ca285e415b59a5b.png

Calinski-Harabasz分数:

#> the Calinski-Harabasz scores(k=4) is:  158961.98176157777

有结果可知:k=4时的Calinski-Harabasz分数最高,因此选择簇类个数为4 。

6. k-means聚类算法不适用的几个场景

k_means算法假设数据是各向同性的,即不同簇类的协方差是相等的,通俗讲就是样本数据落在各个方向的概率是相等的。

1)若样本数据是各向异性的,那么k-means算法的效果较差。

生成一组各向异性的样本数据:

import numpy as np
import matplotlib.pyplot as pltfrom sklearn.cluster import KMeans
from sklearn.datasets import make_blobsplt.figure(figsize=(6, 6))n_samples = 1500
random_state = 170
X, y = make_blobs(n_samples=n_samples, random_state=random_state)# 生成各项异性的数据
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
X_aniso = np.dot(X, transformation)plt.scatter(X_aniso[:, 0], X_aniso[:, 1], marker='.')
plt.title("Anisotropicly Distributed Blobs")plt.show()

生成样本数据的散点图效果:

36faf9e5f0848577da82a364904d10f0.png

根据散点图分布,我们用簇类数k=3训练样本数据:

# k =3训练数据,输出散点效果图
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_aniso)
plt.scatter(X_aniso[:, 0], X_aniso[:, 1], marker='.',c=y_pred)
plt.title("clustering scatter distributed k=3")
plt.show()

聚类效果图:

023fcb7d120fe073fd5827bcffcf67c8.png

由上图可知聚类效果很差。

2)当样本数据集是非凸数据集时,k-means聚类效果较差:

首先生成非凸数据集:

# 非凸数据集
plt.figure(figsize=[6,6])
from sklearn import cluster,datasets
n_samples = 1500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=.5, noise=.05)
plt.scatter(noisy_circles[0][:,0],noisy_circles[0][:,1],marker='.')
plt.title("non-convex datasets")
plt.show()

散点图效果:

2142ce9333a6fc7c0508540d3855ecc0.jpeg

根据散点图分布,我们用簇类数k=2训练样本数据:

# k=2训练数据
y_pred = KMeans(n_clusters=2, random_state=random_state).fit_predict(noisy_circles[0])
plt.scatter(noisy_circles[0][:, 0], noisy_circles[0][:, 1], marker='.',c=y_pred)
plt.title("non-convex k-means clustering")
plt.show()

散点图聚类效果:

60fc35227c6a81ed7d494affdee45a76.jpeg

由上图可知聚类效果很差。

3)当训练数据集各个簇类的标准差不相等时,k-means聚类效果不好。

# 构建不同方差的各簇类数据,标准差分别为1.0,2.5,0.5
X_varied, y_varied = make_blobs(n_samples=n_samples,cluster_std=[1.0, 2.5, 0.5],random_state=random_state)
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_varied)plt.scatter(X_varied[:, 0], X_varied[:, 1], c=y_pred)
plt.title("Unequal Variance")
plt.show()

由下图可知聚类效果不好:

12e9b482b3fe22515b3a4ef37dd52232.jpeg

4)若各簇类的样本数相差比较大,聚类性能较差。

产生三个样本数分别为500,10,10的簇类:

n_samples = 1500
random_state = 170
# 产生三个簇类,每个簇类样本数是500
X, y = make_blobs(n_samples=n_samples, random_state=random_state)
# 三个簇类的样本数分别为500,100,10,查看聚类效果
X_filtered = np.vstack((X[y == 0][:500], X[y == 1][:100], X[y == 2][:5]))
plt.scatter(X_filtered[:, 0], X_filtered[:, 1], marker='.')
plt.title("Unequal Variance")
plt.show()

散点图分布:

208765b118d780af06958305e02a556d.png

运用k-means对其聚类:

y_pred = KMeans(n_clusters=3,random_state=random_state).fit_predict(X_filtered)
plt.scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_pred,marker='.')
plt.title("Unevenly Sized Blobs")plt.show()

效果图如下:

4d0635c763abe402b6a42a1637aea642.png

5) 若数据维度很大时,运行时间很长,可以考虑先用pca降维。

# 产生100维的15000个样本
n_samples = 15000
random_state = 170
plt.figure(figsize=[10,6])
t0=time.time()
# 产生三个簇类,每个簇类样本数是500
X, y = make_blobs(n_samples=n_samples, n_features=100,random_state=random_state)
y_pred = KMeans(n_clusters=3,random_state=random_state).fit_predict(X)
t1 =time.time()-t0
scores1 = metrics.calinski_harabaz_score(X,y)
print("no feature dimonsion reduction scores = ",scores1)
print("no feature dimonsion reduction runtime = ",t1)

输出聚类效果和运行时间:

no feature dimonsion reduction scores =  164709.2183791984
no feature dimonsion reduction runtime =  0.5700197219848633

数据先进行PCA降维再用k-means聚类,

# 数据先pca降维,再k-means聚类
from sklearn.decomposition import PCA
pca = PCA(n_components=0.8)
s=pca.fit_transform(X)
t0=time.time()
y_pred = KMeans(n_clusters=3,random_state=random_state).fit_predict(s)
t1 =time.time()-t0
print("feature dimonsion reduction scores = ",scores1)
print("feature dimonsion reduction runtime = ",t1)

输出聚类效果和运行时间:

feature dimonsion reduction scores =  164709.2183791984
feature dimonsion reduction runtime =  0.0630037784576416

由结果对比可知,聚类效果相差无几的情况下,运行时间大大降低了。

7. k-means与knn的区别

k-means是最简单的非监督分类算法,knn是最简单的监督分类算法,初学者学完监督学习章节再去学非监督章节会感觉似曾相识,原因可能都是用距离作为评价样本间的相似度。下面列举几个区别的地方:

1)knn是监督学习方法,k-means是非监督学习方法,因此knn需要样本的标记类,k-means不需要;

2)knn不需要训练,只要找到距离测试样本最近的k个样本,根据k个样本的类别给出分类结果;k-means需要训练,训练的目的是得到每个簇类的均值向量(质心),根据质心给出测试数据的分类结果;

8. 小结

k-means算法简单且在一些大样本数据表现较好而得到广泛的应用,本文也列举了k-means不适用的几个场景,其他聚类算法可能很好的解决k-means所不能解决的场景,不同的聚类算法有不同的优缺点,后续文章会持续介绍聚类算法,希望这篇k-means总结文章能帮到您。

参考

https://scikit-learn.org/stable/modules/clustering.html#clustering

https://www.cnblogs.com/pinard/p/6169370.html

 

好消息!

小白学视觉知识星球

开始面向外开放啦👇👇👇

 

7d059f632c1dfc8eb0b173ff20c409b4.jpeg

下载1:OpenCV-Contrib扩展模块中文版教程在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。交流群欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

http://chatgpt.dhexx.cn/article/fdIJypHp.shtml

相关文章

LaneAF | 利用Affinity Field聚类进行车道线实例分割

点击上方“计算机视觉工坊”,选择“星标” 干货第一时间送达 论文:https://arxiv.org/abs/2103.12040 开源代码:https://github.com/sel118/LaneAF 0 动机 车道线检测对于辅助驾驶、自动驾驶至关重要。全球范围内多种多样的车道线以及复杂的道…

机器学习 --- 聚类性能评估指标

第1关:外部指标 任务描述 本关任务:填写 python 代码,完成 calc_JC 函数、calc_FM 函数和 calc_Rand 函数分别实现计算 JC系数、FM 指数 和 Rand 指数 。 相关知识 为了完成本关任务,你需要掌握: JC 系数; FM 指数&…

如何用 DBSCAN 聚类算法做数据分析?

DBSCAN属于无监督学习算法,无监督算法的内涵是观察无标签数据集自动发现隐藏结构和层次,在无标签数据中寻找隐藏规律。 聚类模型在数据分析当中的应用:既可以作为一个单独过程,用于寻找数据内在规律,也可以作为分类等…

激光点云的物体聚类

点击上方“小白学视觉”,选择加"星标"或“置顶” 重磅干货,第一时间送达 文章导读 本文针对自动驾驶中三维点云的道路目标聚类进行讲解,从聚类算法的原理出发,介绍几种常用的点云障碍物聚类算法,并对比分析算…

K-means聚类算法

实训目标 本实训项目介绍无监督学习中,使用最广泛的 K-means 聚类算法。 先修知识 本实训项目假设,你已经掌握了初步的 Python 程序设计的基础知识。学习者若有一些 numpy 的使用经验,则可更快速地通过实训。 实训知识点 欧几里得距离 估算簇…

一文详解激光点云的物体聚类

点击上方“3D视觉工坊”,选择“星标” 干货第一时间送达 文章导读 本文针对自动驾驶中三维点云的道路目标聚类进行讲解,从聚类算法的原理出发,介绍几种常用的点云障碍物聚类算法,并对比分析算法的优劣和适用场景,从工程…

[计算机毕业设计]模糊聚类算法

前言 📅大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科同学来说是充满挑战。为帮助大家顺利通过…

51nod-1548:欧姆诺姆和糖果

1548 欧姆诺姆和糖果 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 一天,欧姆诺诺姆来到了朋友家里,他发现了许多糖果。有蓝色和红色两种。他知道每颗…

android自动导入包快捷键,Android studio 自动导入(全部)包 import

http://blog.csdn.net/buaaroid/article/details/44979629 1 Android studio 只有import单个包的快捷键:Alt+Enter。没有Eclipse下的快速导入包的快捷键Ctrl+Shift+O。 2 但Android studio设置里有一项Auto Import自动导入功能。设置过程如下: Android studio --> File--&…

舍友打一把游戏的时间,我实现了一个selenium自动化测试并把数据保存到MySQL

文章目录 前言最终效果开发环境selenium元素定位方法页面分析思路分析实现步骤运行结果以下是全部代码 前言 很久没有玩selenium自动化测试了,近日在学习中都是在忙于学习新的知识点,所以呢今天就来写个selenium自动化测试的案例吧。有没有人疑惑&#…

51nod P1381 硬币游戏【数学】

题目 思路 比较简单. 参考代码 #include<iostream> #include<cstdio> using namespace std; int T,n; int main() {scanf("%d",&T);while(T--){scanf("%d",&n);printf("%d\n",2*n);}return 0; }

51nod3061 车

题目 题目链接 解题思路 提一种不需要生成树的解法。 我们将询问挂到点上&#xff0c;使用启发式合并的并查集。当询问的两边合并到一起时&#xff0c;我们就得到了答案。 整体复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2​n)。 代码 #include <cstdio> #include &…

51nod 1279 扔盘子

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1279 题目: 有一口井,井的高度为N,每隔1个单位它的宽度有变化。现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去)。 盘子有几种命运:1、掉到…

51nod 1352:集合计数

1352 集合计数 基准时间限制&#xff1a;1 秒 空间限制&#xff1a;131072 KB 分值: 20 难度&#xff1a;3级算法题 收藏 关注 给出N个固定集合{1&#xff0c;N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足&#xff1a;第一个元素是A的倍数且第二个元素是B的倍数…

51nod 1266 蚂蚁

题目链接&#xff1a;https://www.51nod.com/onlineJudge/questionCode.html#!problemId1266 题目&#xff1a; n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行。当蚂蚁爬到竿子的端点时就会掉落。由于竿子太细&#xff0c;两只蚂蚁相遇时&#xff0c;它们不能交错通过&#xff…

51nod3155 跳房子

3155 跳房子 小华正在和她的小伙伴玩跳房子游戏。这是一个加强版的跳房子&#xff0c;每一行的格子数量可能超过 2 个。 这个游戏需要在地面上画了n排格子&#xff0c;其中第i排包含a[i]个格子。&#xff08;保证两端的这两排仅有一个格子&#xff09; 之后规定两端的这两个格…

Pycharm中用Appium框架编写第一个自动化脚本

一.环境依赖 Node.js appium python jdk Android SDK Appium-Python-Client Appium-doctor 二.环境搭建 提醒&#xff1a;安装路径如果要自定义的话尽量不要出现中文&#xff0c;不然很容易出现各种报错&#xff01; cmd尽量用管理员身份运行 1.Node.js 下载地址&am…

软件行为(五)之数据存储

笔者愚见&#xff1a;数据的存储方式是软件行为中的重中之重。 存储数据大约有4个地方&#xff1a;寄存器、高速缓存、内存及硬盘等。其中cpu对数据的访问速度也是依次降低&#xff0c;如下图 上图从上到下也是cpu访问数据的顺序&#xff0c;CPU的数据去寄存区去拿&#xff0c…

探究业界云存储平台(1):开源的软件定义存储—CoprHD

在接下来的两章中&#xff0c;我将分别为大家介绍与分析三款软件定义存储解决方案&#xff1a;CoprHD、Ceph与ScaleIO&#xff0c;并对后两者进行性能比较分析。 一、开源的软件定义存储—CoprHD 了解开源的CoprHD&#xff08;CoprHD&#xff09;&#xff0c;需要先了解EMC V…

软件定义存储2.0,谁领风骚?

关注我们牛年牛气冲天 中国的软件定义存储&#xff08;SDS&#xff09;市场就像是早上八九点钟的太阳&#xff0c;那样耀眼&#xff0c;生机勃勃&#xff0c;富有朝气。IDC的报告显示&#xff0c;2020年全年&#xff0c;中国SDS市场规模同比增长51.7%&#xff0c;相比2019年&am…