github:kmeans代码实现1kmeans代码实现2(包含二分k-means)
本文算法均使用python3实现


1 聚类算法

  对于"监督学习"(supervised learning),其训练样本是带有标记信息的,并且监督学习的目的是:对带有标记的数据集进行模型学习,从而便于对新的样本进行分类。而在“无监督学习”(unsupervised learning)中,训练样本的标记信息是未知的目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律,为进一步的数据分析提供基础。对于无监督学习,应用最广的便是"聚类"(clustering)。
  “聚类算法”试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“簇”(cluster),通过这样的划分,每个簇可能对应于一些潜在的概念或类别。
  我们可以通过下面这个图来理解:

  上图是未做标记的样本集,通过他们的分布,我们很容易对上图中的样本做出以下几种划分。
  当需要将其划分为两个簇时,即 $ k=2 $ 时:

  当需要将其划分为四个簇时,即 $ k=4 $ 时:

  那么计算机是如何进行这样的划分的呢?这就需要聚类算法来进行实现了。本文主要针对聚类算法中的一种——kmeans算法进行介绍。


2 kmeans算法

  kmeans算法又名k均值算法。其算法思想大致为:先从样本集中随机选取 $ k $ 个样本作为簇中心,并计算所有样本与这 $ k $ 个“簇中心”的距离,对于每一个样本,将其划分到与其距离最近的“簇中心”所在的簇中,对于新的簇计算各个簇的新的“簇中心”。
  根据以上描述,我们大致可以猜测到实现kmeans算法的主要三点:
  (1)簇个数 $ k $ 的选择
  (2)各个样本点到“簇中心”的距离
  (3)根据新划分的簇,更新“簇中心”

2.1 kmeans算法要点

  (1) $ k $ 值的选择
     $ k $ 的选择一般是按照实际需求进行决定,或在实现算法时直接给定 $ k $ 值。
  (2) 距离的度量
     给定样本 $ x^{(i)} = \lbrace x_1^{(i)},x_2^{(i)},,...,x_n^{(i)}, \rbrace 与 x^{(j)} = \lbrace x_1^{(j)},x_2^{(j)},,...,x_n^{(j)}, \rbrace ,其中 i,j=1,2,...,m,表示样本数,n表示特征数 $ 。距离的度量方法主要分为以下几种:
    (2.1)有序属性距离度量(离散属性 $ \lbrace1,2,3 \rbrace $ 或连续属性):
      闵可夫斯基距离(Minkowski distance): \[ dist_{mk}(x^{(i)},x^{(j)})=(\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}|^p)^{\frac{1}{p}} \]
      欧氏距离(Euclidean distance),即当 $ p=2 $ 时的闵可夫斯基距离: \[ dist_{ed}(x^{(i)},x^{(j)})=||x^{(i)}-x^{(j)}||_2=\sqrt{\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}|^2} \]
      曼哈顿距离(Manhattan distance),即当 $ p=1 $ 时的闵可夫斯基距离: \[ dist_{man}(x^{(i)},x^{(j)})=||x^{(i)}-x^{(j)}||_1=\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}| \]
    (2.2)无序属性距离度量(比如{飞机,火车,轮船}):
      VDM(Value Difference Metric): \[ VDM_p(x_u^{(i)},x_u^{(j)}) = \sum_{z=1}^k \left|\frac{m_{u,x_u^{(i)},z}}{m_{u,x_u^{(i)}}} - \frac{m_{u,x_u^{(j)},z}}{m_{u,x_u^{(j)}}} \right|^p \]
      其中 $ m_{u,x_u^{(i)}} $ 表示在属性 $ u $ 上取值为 $ x_u^{(i)} $ 的样本数, $ m_{u,x_u^{(i)},z} $ 表示在第 $ z $ 个样本簇中属性 $ u $ 上取值为 $ x_u^{(i)} $ 的样本数, $ VDM_p(x_u^{(i)},x_u^{(j)}) $ 表示在属性 $ u $ 上两个离散值 $ x_u^{(i)} 与 x_u^{(i)} $ 的 $ VDM $ 距离 。
    (2.3)混合属性距离度量,即为有序与无序的结合: \[ MinkovDM_p(x^{(i)},x^{(j)}) = \left( \sum_{u=1}^{n_c} | x_u^{(i)} - x_u^{(j)} | ^p + \sum_{u=n_c +1}^n VDM_p (x_u^{(i)},x_u^{(j)}) \right) ^{\frac{1}{p}} \]
      其中含有 $ n_c $ 个有序属性,与 $ n-n_c $ 个无序属性。
    本文数据集为连续属性,因此代码中主要以欧式距离进行距离的度量计算。
  (3) 更新“簇中心”
     对于划分好的各个簇,计算各个簇中的样本点均值,将其均值作为新的簇中心。

2.2 kmeans算法过程


  输入:训练数据集 $ D ={x^{(1)},x^{(2)},...,x^{(m)}}$ ,聚类簇数 $ k $ ;
  过程:函数 $ kMeans(D, k, maxIter) $ .
  1:从 $ D $ 中随机选择 $ k $ 个样本作为初始“簇中心”向量: $ {\mu^{(1)},\mu^{(2)},...,,\mu^{(k)}} $ :
  2:repeat
  3:  令 $ C_i = \emptyset (1 \leq i \leq k ) $
  4:  for $ j= 1,2,...,m $ do
  5:    计算样本 $ x^{(j)} $ 与各“簇中心”向量 $ \mu^{(i)} (1 \leq i \leq k ) $ 的欧式距离
  6:    根据距离最近的“簇中心”向量确定 $ x^{(j)} $ 的簇标记: $ \lambda_j = argmin_{i \in \lbrace 1,2,...,k \rbrace}d_{ji} $
  7:    将样本 $ x^{(j)} $ 划入相应的簇: $ C_{\lambda_j} = C_{\lambda_j} \bigcup \lbrace x^{(j)} \rbrace $ ;
  8:  end for
  9:  for $ i= 1,2,...,k $ do
  10:    计算新“簇中心”向量: $ (\mu^{(i)})' = \frac{1}{|C_i|} \sum_{x \in C_i}x $ ;
  11:    if $ (\mu^{(i)})' = \mu^{(i)} $ then
  12:      将当前“簇中心”向量 $ \mu^{(i)} $ 更新为 $ (\mu^{(i)})' $
  13:    else
  14:      保持当前均值向量不变
  15:    end if
  16:  end for
  17:  else
  18:until 当前“簇中心”向量均未更新
  输出:簇划分 $ C={C_1,C_2,...,C_K} $


  为避免运行时间过长,通常设置一个最大运行轮数或最小调整幅度阈值,若达到最大轮数或调整幅度小于阈值,则停止运行。
  过程如下图:

2.2 kmeans算法分析

  kmeans算法由于初始“簇中心”点是随机选取的,因此最终求得的簇的划分与随机选取的“簇中心”有关,也就是说,可能会造成多种 $ k $ 个簇的划分情况。这是因为kmeans算法收敛到了局部最小值,而非全局最小值。


3 二分k-means算法

  基于kmeans算法容易使得结果为局部最小值而非全局最小值这一缺陷,对算法加以改进。使用一种用于度量聚类效果的指标SSE(Sum of Squared Error),即对于第 $ i $ 个簇,其SSE为各个样本点到“簇中心”点的距离的平方的和,SSE值越小表示数据点越接近于它们的“簇中心”点,聚类效果也就越好。以此作为划分簇的标准。
  算法思想是:先将整个样本集作为一个簇,该“簇中心”点向量为所有样本点的均值,计算此时的SSE。若此时簇个数小于 $ k $ ,对每一个簇进行kmeans聚类($ k=2 $) ,计算将每一个簇一分为二后的总误差SSE,选择SSE最小的那个簇进行划分操作。

3.1 kmeans算法过程


  输入:训练数据集 $ D ={x^{(1)},x^{(2)},...,x^{(m)}}$ ,聚类簇数 $ k $ ;
  过程:函数 $ kMeans(D, k, maxIter) $ .
  1:将所有点看做一个簇,计算此时“簇中心”向量:$ \mu^{(1)} = \frac{1}{m} \sum_{x \in D}x $
  2:while $ “簇中心”个数h < k $ :
  3:  for $ i= 1,2,...,h $ do
  4:    将第 $ i $ 个簇使用 kmeans算法进行划分,其中 $ k = 2 $
  5:    计算划分后的误差平方和 $ SSE_i $
  5:  比较 $ k $ 种划分的SSE值,选择SSE值最小的那种簇划分进行划分
  5:  更新簇的分配结果
  5:  添加新的“簇中心”
  18:until 当前“簇中心”个数达到 $ k $
  输出:簇划分 $ C={C_1,C_2,...,C_K} $


3.2 二分k-means算法分析

  二分k-means算法不再随机选取簇中心,而是从一个簇出发,根据聚类效果度量指标SSE来判断下一步应该对哪一个簇进行划分,因此该方法不会收敛到局部最小值,而是收敛到全局最小值。


引用及参考:
[1]《机器学习》周志华著
[2]《机器学习实战》Peter Harrington著
[3]https://blog.csdn.net/google19890102/article/details/26149927

写在最后:本文参考以上资料进行整合与总结,属于原创,文章中可能出现理解不当的地方,若有所见解或异议可在下方评论,谢谢!
若需转载请注明https://www.cnblogs.com/lliuye/p/9144312.html

kmeans算法理解及代码实现的更多相关文章

  1. [数据挖掘] - 聚类算法:K-means算法理解及SparkCore实现

    聚类算法是机器学习中的一大重要算法,也是我们掌握机器学习的必须算法,下面对聚类算法中的K-means算法做一个简单的描述: 一.概述 K-means算法属于聚类算法中的直接聚类算法.给定一个对象(或记 ...

  2. PCA算法理解及代码实现

    github:PCA代码实现.PCA应用 本文算法均使用python3实现 1. 数据降维   在实际生产生活中,我们所获得的数据集在特征上往往具有很高的维度,对高维度的数据进行处理时消耗的时间很大, ...

  3. k邻近算法理解及代码实现

    github:代码实现 本文算法均使用python3实现 1 KNN   KNN(k-nearest neighbor, k近邻法),故名思议,是根据最近的 $ k $ 个邻居来判断未知点属于哪个类别 ...

  4. 【K-means算法】matlab代码实例学习

    1. MATLAB函数Kmeans 使用方法:Idx=Kmeans(X,K)[Idx,C]=Kmeans(X,K) [Idx,C,sumD]=Kmeans(X,K) [Idx,C,sumD,D]=Km ...

  5. Kmeans算法的应用实例(Matlab版本)

    K-means是一种经典的聚类算法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类.通过迭代的方法,逐次更新各聚类中心的值,直至得到最 ...

  6. 【Java】K-means算法Java实现以及图像切割

    1.K-means算法简述以及代码原型 数据挖掘中一个重要算法是K-means.我这里就不做具体介绍.假设感兴趣的话能够移步陈皓的博客: http://www.csdn.net/article/201 ...

  7. weighted Kernel k-means 加权核k均值算法理解及其实现(一)

    那就从k-means开始吧 对于机器学习的新手小白来说,k-means算法应该都会接触到吧.传统的k-means算法是一个硬聚类(因为要指定k这个参数啦)算法.这里利用百度的解释 它是数据点到原型的某 ...

  8. K-Means算法及代码实现

    1.K-Means算法 K-Means算法,也被称为K-平均或K-均值算法,是一种广泛使用的聚类算法.K-Means算法是聚焦于相似的无监督的算法,以距离作为数据对象间相似性度量的标准,即数据对象间的 ...

  9. k-means算法MATLAB和opencv代码

    上一篇博客写了k-means聚类算法和改进的k-means算法.这篇博客就贴出相应的MATLAB和C++代码. 下面是MATLAB代码,实现用k-means进行切割: %%%%%%%%%%%%%%%% ...

随机推荐

  1. nginx 日志记录 自定义详解(分析上报用)

    nginx 日志记录 自定义详解   1.log_format 普通格式 log_format main '$remote_addr - $remote_user [$time_local] $req ...

  2. php的基础知识(四)

    14.数组: 索引数组: 下标就是数字开始的. $arr = ['a','b','c',1,2,3]; 关联数组: $arr = [ 'a' => 'b', 'c' => 'd'; 'e' ...

  3. PHP使用阿里大鱼发送短信验证

    目前,基本上所有的网站注册都要求手机绑定,并通过下发短信验证码方式验证手机的真实性,提高了用户的真实性.但是一般企业单独申请短信行业通道都比较困难,因此选择一家信誉好,稳定性.及时性强的第三方短信通道 ...

  4. PADS随记

    在PADS,PCB板设计中,怎么一次就把丝印的大小设置好? CTRL+ALT+F  组合键 打开 选择过滤器(Filter) 如下图 去掉其他的勾选,只选择 Labels . 之后在板子上鼠标拖动选上 ...

  5. for循环删除列表中元素遇到的漏删的问题(python)

    问题描述:python中通过for循环来删除列表中的两个相邻的元素,存在漏删的问题 比如说下面的例子,准备删掉2和3,但是结果是2删掉了,3没删掉 是因为把2删掉后3的下标就变成了1,但是原本下标为1 ...

  6. HyperLedger Fabric 1.4 Solo模式简介(10.1)

    Solo模式指单节点通信模式,该环境中只有一个排序(orderer)服务,从节点(peer)发送来的消息由一个orderer进行排序和产生区块:由于排序(orderer)服务只有一个orderer为所 ...

  7. CSS基础part1

    CSS 概述CSS 指层叠样式表 (Cascading Style Sheets),样式定义了如何显示 HTML文件中的标签元素,CSS是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标 ...

  8. 【NAS】CIFS用户场景需求分析

    1.everyone用户 1.1: 场景描述:共享目录为rule,所有用户都可以查看,但是不能修改: 解决方法:在smb.conf里配置read only = yes,具体示例如下: [rule] p ...

  9. 韩国KT软件NB-IOT开发记录V150(2)IOT maker通信相关

    1. 测试的AT指令,创建端口和IP地址链接 AT#IMINIT=," 开始连接 AT#IMCONN 创建object ID AT#IMOBJMETA=,," 发送数据 AT#IM ...

  10. Ruby 基础教程 1-2

    1.数组 创建 arrayname=[] arrayname=["1",12,"23"] 访问 arrayname[index] 更新 arrayname[in ...