好久之前写过K-Means, 但写的极其丑陋,使用的时候还得用 sklearn.cluster.KMeans 包来干。最近需要手撕k-Means,自己也受不了多重for 循环这么disgusting的方式。sklearn.cluster.KMeans等包加入了相当多细节优化和向量化计算,同时也想能否用 numpy 来原生实现更高效的加速。在网上找了半天,终于看到这篇简洁又高效的numpy实现了。

Clustering and NumPy​ixora.io

K-Means原理很简单。按照西瓜书的定义,就是在给定样本集

​,找出簇中心
​来最小化平方误差:

说人话就是找到​

个类中心,让所有样本被分在簇内的话样本相似度越高。但是这是个NP难问题,通常使用迭代优化来近似寻找
​个类中心,也就是只要误差在可接受范围内就认为找到了所有样本到类中心的最小化误差。

这里我们首先随机或者基于某种策略生成​

个簇中心,然后计算所有数据与 ​
个簇中心的距离,将数据根据与其相邻最近的簇中心分配为某个聚类,之后再次根据新的划分计算簇中心... 这样周而复始直到簇中心不再变化或者计算超出预期轮次,流程图如下:

原理上较为简单,一般都可以简单实现。这里分析一下优化的点,计算所有样本与簇中心的时候,往往会使用 多重for循环 来遍历所有样本,并重新计算类中心。实际上 numpy 提供了广播机制(broadcasting)来进行高效矩阵计算,这在各个小型神经网络与计算图框架中均使用到了(MyGrad, micrograd, tinygrad),一直没有深入底层研究过。结合其他博主的文章来先看一看:

司南牧:2个规则弄懂numpy的broadcast广播机制​zhuanlan.zhihu.com

这篇博客

Clustering and NumPy​ixora.io

就利用 broadcasting 来进行的计算,实现上非常高效,我们对关键部分进行解析:

import numpy as np
def kmeans(data, k=3, normalize=False, limit=500):# normalize 数据if normalize:stats = (data.mean(axis=0), data.std(axis=0))data = (data - stats[0]) / stats[1]# 直接将前K个数据当成簇中心centers = data[:k]for i in range(limit):# 首先利用广播机制计算每个样本到簇中心的距离,之后根据最小距离重新归类classifications = np.argmin(((data[:, :, None] - centers.T[None, :, :])**2).sum(axis=1), axis=1)# 对每个新的簇计算簇中心new_centers = np.array([data[classifications == j, :].mean(axis=0) for j in range(k)])# 簇中心不再移动的话,结束循环if (new_centers == centers).all():breakelse:centers = new_centerselse:# 如果在for循环里正常结束,下面不会执行raise RuntimeError(f"Clustering algorithm did not complete within {limit} iterations")# 如果normalize了数据,簇中心会反向 scaled 到原来大小if normalize:centers = centers * stats[1] + stats[0]return classifications, centers

接下来就是产生一些随机数来测试一下吧

data = np.random.rand(200, 2)
classifications, centers = kmeans(data, k=5)

将聚类的结果可视化出来,每个类分别上不同的色,其中每个簇中心用黑色三角表示:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt%matplotlib inlineplt.figure(figsize=(12, 8))
plt.scatter(x=data[:, 0], y=data[:, 1], s=100, c=classifications)
plt.scatter(x=centers[:, 0], y=centers[:, 1], s=500, c='k', marker='^');
# 16轮迭代结束

k-means算法对每个数据维数的相对尺度很敏感。如果某个维度是更大,距离函数会在该维度的计算权重会更大一些。直观一些,当我们将数据第一维扩大10倍后,观察一下:

data = np.random.rand(200, 2)
data[:, 0] *= 10  # 第一维扩大10倍classifications, centers = kmeans(data, k=5)plt.figure(figsize=(12, 8))
plt.scatter(x=data[:, 0], y=data[:, 1], s=100, c=classifications)
plt.scatter(x=centers[:, 0], y=centers[:, 1], s=500, c='k', marker='^');
# 13轮迭代结束

数据在垂直方向分成了5类,很显然因为x轴的权重大于y轴(第1维度扩大了10倍)。使用归一化参数对数据进行归一化,可以得到更好的结果,我们可视化一下:

classifications, centers = kmeans(data, normalize=True, k=5)plt.figure(figsize=(12, 8))
plt.scatter(x=data[:, 0], y=data[:, 1], s=100, c=classifications)
plt.scatter(x=centers[:, 0], y=centers[:, 1], s=500, c='k', marker='^');
# 9轮迭代结束

该算法还可以对2维以上数据进行聚类,下面进行3维聚类:

data = np.random.rand(200, 3)classifications, centers = kmeans(data, normalize=True, k=5)fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')ax.scatter(data[:, 0], data[:, 1], data[:, 2], c=classifications, s=100)
ax.scatter(centers[:, 0], centers[:, 1], centers[:, 2], s=500, c='k', marker='^');
# 8轮迭代

numpy归一化_使用numpy 高效实现K-Means聚类相关推荐

  1. OpenCV的k - means聚类 -对图片进行颜色量化

    OpenCV的k - means聚类 目标 学习使用cv2.kmeans()数据聚类函数OpenCV 理解参数 输入参数 样品:它应该的np.float32数据类型,每个特性应该被放在一个单独的列. ...

  2. OpenCV官方文档 理解k - means聚类

    理解k - means聚类 目标 在这一章中,我们将了解k - means聚类的概念,它是如何工作等. 理论 我们将这个处理是常用的一个例子. t恤尺寸问题 考虑一个公司要发布一个新模型的t恤. 显然 ...

  3. numpy 随机数_数据分析numpy基础看着一篇就够了

    1,Numpy基础数据结构 2,Numpy通用函数 3,Numpy索引及切片 4,Numpy随机数 5,Numpy数据的输入输出 1,Numpy基础数据结构 NumPy数组是一个多维数组对象,称为nd ...

  4. k means聚类算法_K-Means 聚类算法 20210108

    说到聚类,应先理解聚类和分类的区别 聚类和分类最大的不同在于:分类的目标是事先已知的,而聚类则不一样,聚类事先不知道目标变量是什么,类别没有像分类那样被预先定义出来. K-Means 聚类算法有很多种 ...

  5. numpy 归一化_归一化(MinMax)和标准化(Standard)的区别

    此文参考https://blog.csdn.net/u010947534/article/details/86632819 定义上的区别 归一化:将数据的值压缩到0到1之间,公式如下 标准化:将数据所 ...

  6. numpy 归一化_图卷积网络到底怎么做,这是一份极简的Numpy实现

    由于图结构非常复杂且信息量很大,因此对于图的机器学习是一项艰巨的任务.本文介绍了如何使用图卷积网络(GCN)对图进行深度学习,GCN 是一种可直接作用于图并利用其结构信息的强大神经网络.本文将介绍 G ...

  7. numpy 最大值_使用 NumPy 让你的 Python 科学计算更高效

    具体的原理我也不大懂,简单理解就是Numpy的计算效率更高一些. Numpy里有两个对象: ndarray,实际上就是多维数组的含义,在Numpy数组中,维数称为秩(rank),一维数组的秩为 1,二 ...

  8. python 创建空的numpy数组_真假美猴王-Numpy数据与Python数组的区别与联系

    Numpy,是python中的一个矩阵计算包,功能类似matlab的矩阵计算.Numpy的诞生弥补了下面提到的两项的不足,numpy提供了两种基本的对象:ndarray(N-dimensional a ...

  9. python引用numpy出错_引用numpy出错详解及解决方法

    numpy出错 解决方案 Problem: how to import numpy in subdirectory? Import error of numpy within subfolder. 错 ...

最新文章

  1. Linux Yum命令(转)
  2. R语言文件下载:谁来帮我把这个128个音频下载一下
  3. linux 命令行简介
  4. springboot项目 访问不到静态资源css
  5. Payment Terms 付款条件
  6. 求水仙花_500万株水仙花争相绽放,这个日本小岛人少冬天还能看花!| 日本淡路岛...
  7. C++实现拓扑排序(邻接表存储,栈实现)
  8. 【PAT】B1004 成绩排名
  9. R语言系列:自定义function
  10. pythonjs语法_javascript基础语法(上)
  11. 湖北省土壤有机质空间分布数据
  12. Android P 缩短screencap时间
  13. word文档图片画红线_Word文档怎么在图片内画线?
  14. OSChina 周三乱弹 ——找女朋友都是双胞胎
  15. PTA 租用游艇问题
  16. python在哪里设置改成中文版_pycharm如何设置成中文
  17. 《容忍与自由》读后感
  18. 如何选购合适的IPKVM切换器
  19. 浅入深SpEL表达式注入漏洞总结
  20. Deep Learning for Depression Recognition with Audiovisual Cues: A Review

热门文章

  1. 不做在线电商,或许才是永辉超市的未来
  2. cvs update 用法_WinCVS的配置与使用方法
  3. c语言仿ce内存搜索工 源代码_C语言函数库:动态库和静态库优缺点比较
  4. Python用两个骰子玩掷骰子的游戏。本金为10元,当掷出“7”即获得奖金4元,否则扣除1元。编程测算玩到多少手时钱全部输完,及哪一手时钱数最多。
  5. Python动态类和动态方法的创建和调用
  6. python去掉txt文件行尾换行
  7. Python教程:collections的deque()方法
  8. Python的itertools.product 方法
  9. java创建阻塞_如何从HttpsURLConnection创建Java非阻塞InputStream?
  10. ubuntu apt-get指令和apt指令的区别?