1. 聚类与分类的区别:

首先要来了解的一个概念就是聚类,简单地说就是把相似的东西分到一组,同 Classification (分类)不同,对于一个 classifier ,通常需要你告诉它“这个东西被分为某某类”这样一些例子,理想情况下,一个 classifier 会从它得到的训练集中进行“学习”,从而具备对未知数据进行分类的能力,这种提供训练数据的过程通常叫做 supervised learning (监督学习),而在聚类的时候,我们并不关心某一类是什么,我们需要实现的目标只是把相似的东西聚到一起,因此,一个聚类算法通常只需要知道如何计算相似 度就可以开始工作了,因此 clustering 通常并不需要使用训练数据进行学习,这在 Machine Learning 中被称作 unsupervised learning (无监督学习)。

我们经常接触到的聚类分析,一般都是数值聚类,一种常见的做法是同时提取 N 种特征,将它们放在一起组成一个 N 维向量,从而得到一个从原始数据集合到 N 维向量空间的映射——你总是需要显式地或者隐式地完成这样一个过程,然后基于某种规则进行分类,在该规则下,同组分类具有最大的相似性。

  假设我们提取到原始数据的集合为(x1, x2, …, xn),并且每个xi为d维的向量,K-means聚类的目的就是,在给定分类组数k(k ≤ n)值的条件下,将原始数据分成k类 
S = {S1, S2, …, Sk},在数值模型上,即对以下表达式求最小值:

这里μi 表示分类S的平均值。

说明:给定K,聚类完成后,对于每个类,对该类中的所有样本点到该类中心点的距离的平方求和,记为sum,对每个类都这样求和,然后把所有类的

sum加起来,总和记为SUM,聚类Kmeans算法就是要使得SUM最小。

  那么在计算机编程中,其又是如何实现的呢?其算法步骤一般如下:

1、从D中随机取k个元素,作为k个簇的各自的中心。

2、分别计算剩下的元素到k个簇中心的相异度,将这些元素分别划归到相异度最低的簇。

3、根据聚类结果,重新计算k个簇各自的中心,计算方法是取簇中所有元素各自维度的算术平均数。

4、将D中全部元素按照新的中心重新聚类。

5、重复第4步,直到聚类结果不再变化。

6、将结果输出。

  用数学表达式来说,

设我们一共有 N 个数据点需要分为 K 个 cluster ,k-means 要做的就是最小化

这个函数,其中  在数据点 n 被归类到 cluster k 的时候为 1 ,否则为 0 。即上面的J即为最上面的SUM,直接寻找  和  来最小化  并不容易,不过我们可以采取迭代的办法:先固定  ,选择最优的  ,很容易看出,只要将数据点归类到离他最近的那个中心就能保证  最小。下一步则固定 ,再求最优的 。将  对  求导并令导数等于零,很容易得到  最小的时候  应该满足:

其中  在数据点 n 被归类到 cluster k 的时候为 1,即上面的分母就是类cluster k中样本点数,而分子为该分类中所有样本点的和

亦即  的值应当是所有 cluster k 中的数据点的平均值。由于每一次迭代都是取到  的最小值,因此  只会不断地减小(或者不变),而不会增加,这保证了 k-means 最终会到达一个极小值。虽然 k-means 并不能保证总是能得到全局最优解,但是对于这样的问题,像 k-means 这种复杂度的算法,这样的结果已经是很不错的了。

2. 实现:

注:该实现用的是opencv中的一个函数:cvKMeans2函数

代码来源:http://www.cnblogs.com/moondark/archive/2012/03/08/2385870.html

  1. </pre><p></p><p style="margin:15px auto 10px; padding-top:0px; padding-bottom:0px; line-height:22px; text-align:justify"></p><pre code_snippet_id="500422" snippet_file_name="blog_20141029_2_1547356" name="code" class="cpp" style="font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; font-size: 14px; ">#ifdef _CH_
  2. #pragma package <opencv>
  3. #endif
  4. #define CV_NO_BACKWARD_COMPATIBILITY
  5. // opencv函数手册:http://wiki.opencv.org.cn/index.php/Cxcore数组操作#.E9.9A.8F.E6.9C.BA.E6.95.B0.E7.94.9F.E6.88.90
  6. // 代码来源:http://www.cnblogs.com/moondark/archive/2012/03/08/2385870.html
  7. #include "opencv/cv.h"
  8. #include "opencv/highgui.h"
  9. #include <stdio.h>
  10. int main( int argc, char** argv )
  11. {
  12. #define MAX_CLUSTERS 5    //设置类别的颜色,个数(《=5)
  13. CvScalar color_tab[MAX_CLUSTERS];
  14. IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 ); //8位,3通道
  15. CvRNG rng = cvRNG(-1); //4位的有符号数,若4位全为1,则值为-1,即A=1111,A=-1,当转换为无符号数时,则为最大
  16. CvPoint ipt;
  17. color_tab[0] = CV_RGB(255,0,0); //每个类别的颜色标志
  18. color_tab[1] = CV_RGB(0,255,0);
  19. color_tab[2] = CV_RGB(100,100,255);
  20. color_tab[3] = CV_RGB(255,0,255);
  21. color_tab[4] = CV_RGB(255,255,0);
  22. cvNamedWindow( "clusters", 1 );
  23. for(;;)
  24. {
  25. char key;
  26. int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1; //聚类的类别数随机生成,在[1,5]范围内
  27. int i, sample_count = cvRandInt(&rng)%1000 + 1; //样本个数
  28. CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 ); //生成sample_count行,1列且数据类型为32位浮点双通道的数组,样本点数组
  29. CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 );//生成sample_count行,1列且数据类型为32位有符号数单通道的数组,每个样本对应的类别标识数组
  30. cluster_count = MIN(cluster_count, sample_count); //聚类的类别数
  31. /** generate random sample from multigaussian distribution,用多维高斯分布即正态分布来生成随机数 */
  32. for( k = 0; k < cluster_count; k++ )
  33. {
  34. CvPoint center;
  35. CvMat point_chunk;
  36. center.x = cvRandInt(&rng)%img->width;
  37. center.y = cvRandInt(&rng)%img->height;
  38. /*
  39. GetRow, GetRows
  40. 返回数组的一行或在一定跨度内的行
  41. CvMat* cvGetRow( const CvArr* arr, CvMat* submat, int row );
  42. CvMat* cvGetRows( const CvArr* arr, CvMat* submat, int start_row, int end_row, int delta_row=1 );
  43. arr
  44. 输入数组。
  45. submat
  46. 指向返回的子数组头的指针。
  47. row
  48. 被选定行的索引下标,索引下标从0开始。
  49. start_row
  50. 跨度的开始行(包括此行)索引下标,索引下标从0开始。
  51. end_row
  52. 跨度的结束行(不包括此行)索引下标,索引下标从0开始。
  53. delta_row
  54. 在跨度内的索引下标跨步,从开始行到结束行每隔delta_row行提取一行。
  55. */
  56. cvGetRows( points, &point_chunk, k*sample_count/cluster_count,
  57. k == cluster_count - 1 ? sample_count :
  58. (k+1)*sample_count/cluster_count, 1 );
  59. /*
  60. RandArr
  61. 用随机数填充数组并更新 RNG 状态
  62. void cvRandArr( CvRNG* rng, CvArr* arr, int dist_type, CvScalar param1, CvScalar param2 );
  63. rng
  64. 被 cvRNG 初始化的 RNG 状态.
  65. arr
  66. 输出数组
  67. dist_type
  68. 分布类型:
  69. CV_RAND_UNI - 均匀分布
  70. CV_RAND_NORMAL - 正态分布 或者 高斯分布
  71. param1
  72. 分布的第一个参数。如果是均匀分布它是随机数范围的闭下边界。如果是正态分布它是随机数的平均值。
  73. param2
  74. 分布的第二个参数。如果是均匀分布它是随机数范围的开上边界。如果是正态分布它是随机数的标准差。
  75. */
  76. cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL,
  77. cvScalar(center.x,center.y,0,0),
  78. cvScalar(img->width*0.1,img->height*0.1,0,0));
  79. }
  80. /** shuffle samples 即随机打乱样本*/
  81. for( i = 0; i < sample_count/2; i++ )
  82. {
  83. CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
  84. CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
  85. CvPoint2D32f temp;
  86. CV_SWAP( *pt1, *pt2, temp );
  87. }
  88. // 使用Kmeans聚类
  89. /*
  90. int cvKMeans2(const CvArr* samples, int nclusters,
  91.         CvArr* labels, CvTermCriteria termcrit,
  92.         int attempts=1, CvRNG* rng=0,int flags=0,
  93.         CvArr* centers=0,double* compactness=0);
  94. 由于除去已经确定的参数,我们自己需要输入的为:
  95. void cvKMeans2(
  96.   const CvArr* samples, //输入样本的浮点矩阵,每个样本一行。
  97.   int cluster_count,  //所给定的聚类数目
  98.   * labels,    //输出整数向量:每个样本对应的类别标识
  99.   CvTermCriteria termcrit //指定聚类的最大迭代次数和/或精度(两次迭代引起的聚类中心的移动距离)
  100. );
  101. */
  102. // 输出迭代数
  103. printf( "iterations=%d\n", cvKMeans2( points, cluster_count, clusters,
  104. cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0 ),
  105. 5, 0, 0, 0, 0 ));
  106. cvZero( img );
  107. for( i = 0; i < sample_count; i++ ) // 依照样本所属的类别,以不同的颜色画出样本点
  108. {
  109. int cluster_idx = clusters->data.i[i];
  110. ipt.x = (int)points->data.fl[i*2];
  111. ipt.y = (int)points->data.fl[i*2+1];
  112. cvCircle( img, ipt, 2, color_tab[cluster_idx], CV_FILLED, CV_AA, 0 );
  113. }
  114. cvReleaseMat( &points );
  115. cvReleaseMat( &clusters );
  116. cvShowImage( "clusters", img );
  117. key = (char) cvWaitKey(0);
  118. if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
  119. break;
  120. }
  121. cvDestroyWindow( "clusters" );
  122. return 0;
  123. }

效果如下:

转:http://blog.csdn.net/damotiansheng/article/details/40582211

【转】 聚类算法-Kmeans算法的简单实现的更多相关文章

  1. [聚类算法] K-means 算法

    聚类 和 k-means简单概括. 聚类是一种 无监督学习 问题,它的目标就是基于 相似度 将相似的子集聚合在一起. k-means算法是聚类分析中使用最广泛的算法之一.它把n个对象根据它们的属性分为 ...

  2. 数据聚类算法-K-means算法

    深入浅出K-Means算法 摘要: 在数据挖掘中,K-Means算法是一种 cluster analysis 的算法,其主要是来计算数据聚集的算法,主要通过不断地取离种子点最近均值的算法. K-Mea ...

  3. 机器学习--聚类系列--K-means算法

    一.聚类 聚类分析是非监督学习的很重要的领域.所谓非监督学习,就是数据是没有类别标记的,算法要从对原始数据的探索中提取出一定的规律.而聚类分析就是试图将数据集中的样本划分为若干个不相交的子集,每个子集 ...

  4. 机器学习sklearn19.0聚类算法——Kmeans算法

    一.关于聚类及相似度.距离的知识点 二.k-means算法思想与流程 三.sklearn中对于kmeans算法的参数 四.代码示例以及应用的知识点简介 (1)make_blobs:聚类数据生成器 sk ...

  5. 数据挖掘经典算法——K-means算法

    算法描述 K-means算法是一种被广泛使用的基于划分的聚类算法,目的是将n个对象会分成k个簇.算法的具体描述如下: 随机选取k个对象作为簇中心: Do 计算所有对象到这k个簇中心的距离,将距离最近的 ...

  6. 算法 - k-means算法

    一.聚类思想 所谓聚类算法是指将一堆没有标签的数据自动划分成几类的方法,属于无监督学习方法,这个方法要保证同一类的数据有相似的特征,如下图所示:     根据样本之间的距离或者说是相似性(亲疏性),把 ...

  7. GMM算法k-means算法的比较

    1.EM算法 GMM算法是EM算法族的一个具体例子. EM算法解决的问题是:要对数据进行聚类,假定数据服从杂合的几个概率分布,分布的具体参数未知,涉及到的随机变量有两组,其中一组可观测另一组不可观测. ...

  8. 数据挖掘算法——K-means算法

    k-means中文称为K均值聚类算法,在1967年就被提出  所谓聚类就是将物理或者抽象对象的集合分组成为由类似的对象组成的多个簇的过程 聚类生成的组成为簇 簇内部任意两个对象之间具有较高的相似度,不 ...

  9. 聚类算法——KMEANS算法

    聚类概念 无监督问题:我们手里没有标签 聚类:相似的东西分到一组 难点:如何评估,如何调参 基本概念 要得到簇的个数,需要指定K值 质心:均值,即向量各维取平均即可 距离的度量:常用欧几里得距离和余弦 ...

随机推荐

  1. EXP7 网络欺诈技术防范(修改版)

    实践内容 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法. 1.简单应用SET工具建立冒名网站 2.ettercap DNS spoof 3.结合应用两种技术,用DNS s ...

  2. https://blog.csdn.net/dayancn/article/details/54692111

    Ubuntu恢复被删除的文件 昨天一不小心,执行了rm xx  -rf,把一个项目删除了.然后就是各种悔恨,各种自责,这个项目可是一周的工作量啊.最后肯定得解决,于是google搜索发现了恢复神器ex ...

  3. 16 级高代 II 思考题九的七种解法

    16 级高代 II 思考题九  设 $V$ 是数域 $\mathbb{K}$ 上的 $n$ 维线性空间, $\varphi$ 是 $V$ 上的线性变换, $f(\lambda),m(\lambda)$ ...

  4. ChromeDriver与Chrome版本对应关系

    备注: 下载ChromeDriver的时候,可以在notes.txt文件中查看版本对应关系. ----------ChromeDriver v2.29 (2017-04-04)---------- S ...

  5. CentOS 使用 Docker 安装 Sentry

    官网介绍:Sentry是一个实时事件日志记录和汇集的日志平台,其专注于错误监控,以及提取一切事后处理所需的信息.他基于Django开发,目的在于帮助开发人员从散落在多个不同服务器上的日志文件里提取发掘 ...

  6. Python logging 模块学习

    logging example Level When it's used Numeric value DEBUG Detailed information, typically of interest ...

  7. 关于link标签的用法, 不声明rel=stylesheet则无效? 在ff中必须声明rel属性!

    void 无效的, 空的; invalid: 无效的, void 和 invalid 在表示无效的时候, 是一样的, 等同的 the treaty (条约) was declared invalid ...

  8. C++中的string常用函数用法

    标准c++中string类函数介绍   注意不是CString 之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而 ...

  9. Linux/shell: remove adjacent similar patterns

    cat > temp004AA1abcAA2AA3abcAA4abcAA5AA6 awk 'BEGIN {pre=0; str="";} { if(NR==1){     i ...

  10. 题解——牛客网OI赛制测试赛2

    T1 规律题 考虑先全部选中再去重即可 #include <cstdio> #include <algorithm> #include <cstring> #inc ...