转自:http://www.cnblogs.com/lzxwalex/p/7708266.html

C#下实现的基础K-MEANS多维聚类

#本文PDF版下载

C#下实现的基础K-MEANS多维聚类PDF

#本文代码下载

基于K-Means的成绩聚类程序

前言

最近由于上C # 课的时候,老师提到了-我们的课程成绩由几个部分组成.分别是「最终作品展示」「小组合作聊天记录评分」「组内成员匿名互评」「报告书评分」这四项综合评价.老师希望我能够通过这四个项目对所有同学进行聚类,然后根据离每簇的中心距离来评价最终的分数.由于我没有接触过这方面的算法,所以就选了实现较为方便并且直观的聚类方法K-MEANS.所以下文中就会对我这次学习到的一些心得进行分享.由于是C # 课程,所以本次的算法将以C# 为例子进行介绍.

聚类&K-Means

聚类

百科上对于聚类的解释是这样的:
将物理或抽象对象的集合分成由类似的对象组成的多个类的过程被称为聚类.由聚类所生成的簇是一组数据对象的集合,这些对象与同一个簇中的对象彼此相似,与其他簇中的对象相异.
简单的来说聚类就是将相似的归在一起产生一个簇,使不相似的分在不同的簇里.

聚类和分类的区别

分类:从特定的数据中根据人为打上的数据表浅进行数据挖掘,做出判断.是将类别已知.并且样本数据已经做了标记的数据进行归类.是一个有监督的过程.
聚类:目的是分类数据,但是在分类结束前我们都不知道数据是怎么分类的,有什么特点,只是根据算法,自动的将相似性的分类在了一起.数据本身没有标记.本身也没有类别.通过聚类的算法将相似性高的数据通过算法打上的标签归类在一起.是一种无监督的过程.

K-Means算法

K-Means算法是基于距离(我在这次中使用了欧几里德距离)的聚类算法  ,  采用距离或者特征向量作为相似程度的考量,数据之间的距离/向量余弦越接近, 其相似度就越大.在K-Means聚类算法中-簇是由距离较为相近的数据对象构成的,故用K-Means算法的目的是想要得到数据对象相对紧凑且独立的不同簇.

「评分系统」和K-Means的结合

这次老师让我做的就是希望我能通过给出的「最终作品展示」「小组合作聊天记录评分」「组内成员匿名互评」「报告书评分」这四个维度的数据对所有同学的成绩使用K-Means聚成四个类,分别对应90-100/80-90/70-80/60-70/不及格这五个等第.分出登第后,五个类的中心分别是95/85/75/65/55,根据离数据中心的欧几里得距离按比例来决定最终的成绩.这就是老师让我实现的功能.

K-Means的非适用性

K-Means算法适应于连续形式的数据,由于数据的分布不同,有时候就无法分得准确的类,比如下面的两种形式

1.非标准正态分布

K-Means用于表示聚类趋势只是说在数据符合正态分布或偏态不太严重时才是合理的.如果偏态严重,或者有异常的极大极小值,对均数影响很大,这时K-MEANS不能代表聚类的趋势.
故在实际的样本中,我们作出的假设可能会并不适用,这个时候用基础的K-Means算法就不是特别的恰当了.这个时候我们就应该用到一些改进的算法,比如 Kernel K-means和Spectral Clustering.这两种算法会在后面的文章中进行介绍.

2.非均匀分布

由于分布的不均匀,疏密程度就会对中心的选取造成影响.就会偏向左侧较密的地方.如下所示:

K-Means的优点和缺点

优点:

1. 算法简单并且效率很高,迭代次数.
2. K-Means聚类算法的时间复杂度是O(nkt) {n数据量/k簇的个数/t算法迭代次数}故时间复杂度近似为线性.
3. 自身具有优化迭代的特点,通过不断的计算中心来修正聚类结果.
4. 对于数据有着很好的伸缩性.

缺点:

1. 需要指定K的值 我们在每次聚类之前需要指定数据会被分成几类即要有几个中心点.
2. 对于离群值较为敏感 由于在每次聚类之后都要重新生成簇的中心.而中心是根据所有簇种数据对象的”质心”来的,所以当数据集不大的时候,这些离群的特殊点对中心就会产生很大的影响.这可以通过对数据集进行预处理,筛出离群的点.离群的点可以全部归类为第(k+1)类,因为它们本身有着非常独特的性质,是我们分析时候可以研究的对象.
3. 初始点的选取对结果会产生影响 初始的点我们一般通过随机选定,但是随机选出的点可能点和点之间并不合理,会造成最终聚类的结果会不相同.
4. 最终的聚类结果是一个球形的簇 由于使用了欧几里得距离,最终一定是以簇中心为球心(圆心)的一个球形(圆形)的簇.
5. 维度对聚类结果的贡献无法得到 无法确定哪一个维度对聚类结果的产生的影响比较大.

K-Means的一些细节

欧几里德距离

欧几里德距离简称欧式距离,是我们平时经常用到的一个距离度量公式,具体就是基础求距离公式,并且拓展至了n维空间.我们以三维空间举一个例子,如下图所示.A,B点根据欧几里得距离公式算出来的就是中间灰色线上方的距离公式

“质心”公式计算

“质心”的选取是因为每一次聚类后都需要通过簇中的数据对象生成新的中心,而生成新中心的方式就是产生所有数据对象的”质心”.公式也可以拓展至n维,这里我们以3维的空间为例子

A/B/C三个点的”质心”就是图中的灰点,坐标为((X1+X2+X3)/3),(Y1+Y2+Y3)/3,(Z1+Z2+Z3)/3)拓展到n维就是((X1+…+Xn)/n,…,((Z1+…Zn)/n)).

K-Means算法实现步骤

这里我们介绍的是K-Means算法的本身步骤,没有加上任何的优化方式,总共分为 5 步,分别如下:
1. 首先,就像上文中说的一样.K-Means算法必须提供k即簇的树目.使我们能够通过聚类算法得到k个分组
2. 从我们要进行聚类的数据集中随机选择k个点作为每个簇的初始中心
3. 通过一定的计算方法(欧几里德距离)来计算每个数据对象距离每一个簇中心的距离.并且得到距离最近的簇的中心点,那么这个数据对象就被归类到了这个簇中.
4. 当所有的点都被聚类后,对于每一个簇算出新的中心.(通过算法找到”质心”).
5. 迭代3,4两个步骤,直到4步骤选出来的新中心和原来的中心小于某个我们默认的阈值(几乎中心不再发生变化),算法停止.我们已经通过聚类算法得到了我们最终的结果.

接下来我们通过举例子的方法来更好的理解一下K-Means算法,我们随机生成了七个点,它们的位置即坐标如下图所示

很明显,我们如果有监督的将他们分类,那么结果一定是如下图所示的情况

那么我们按照K-Means算法的步骤,看一下聚类的过程是怎么样的.
1.首先我们先随机选择两个点作为簇的中心,就选A1/B3这两个点

2.计算么个数据对象距离各个簇中心的距离
对于A2 - 距A1的距离就是((1-2)^2 + (1-2)^2)^(1/2) = √2/距A2的距离就是((1-6)^2+(1-3)^2)^(1/2) = √29 由于√29>√2,所以A2被归类为以A1为中心的簇,同理,其他的点经过归类后的结果如下图所示:

3.重新计算每个簇的中心
我们现在得到了两个簇,现在我们把每个簇里的数据对象的中心求出来,根据质心的求法,我们可以知道红色A组的新中心是((2+1+3)/3,(2+1+1)/3) = (2,4/3),棕色B组的新中心是((5+6+6+7)/4,(4+4+3+2)/4) = (6,3)这个时候我们发现B的中心就是B3这个点,所以对于B组而言不需要再次进行聚类了.
对于A组我们可以发现,A1,A2,A3距离新的中心(2,4/3)相等,故再进行计算新中心的话中心也不会发生改变,所以聚类停止.
4.最终的聚类结果就是A1/A2/A3一组.B1/B2/B3/B4一组.

K-Means在C#下算法的实现

(在这里我展示的是没有优化过的K-Means实现)

1.首先是初始化中心.

根据我们设定的簇的数量,我们可以随机从所有的数据对象中选择k个点作为初始的中心点.这里只需要使用Random类的Next方法即可,所以此步骤不进行介绍.

2.聚类步骤的实现

代码特点解释:
1. 我的程序是先将数据从Excel的Xls文件中导出到了C#控件中的ListView里,这个控件的名字是:XlsDataSh,在程序的代码里可以看到这个控件的名字.
2. 由于我们的Xls文件中并不是只有这四个项的数据,其中的其他几项是另外的一些信息,有着编号/姓名/学号姓息分别占了ListView的0/1/2这三列,而3-6这四个列分别是对应四个维度的.这就是为什么循环中经常会出现类似for (int k = 3; k < 7; k++)的原意.

我们先来看一下聚类这个方法中的运行步骤,如下所示:

解释:
1. ArrayList中存储的事每一个簇所拥有的数据的编号.所以当我们每一次重新计算出了簇的中心之后,会对数据所在的簇进行重新聚类,故首先我们要把ArrayList中所存储的数据进行清除.
2. 判断簇为0是一个重要的步骤.这也是我“偷懒”了之后用的方法,由于我们的初始中心是随意选择的,所以很有可能选择的数据中心再一次聚类之后没有分得任何的数据点,这时候这个类就是无效的.我们应该对它进行处理,而我用的方法就是偷懒的让它再次随机选定中心,直到每个类都一定能分到其他的数据点.
3. ClassNum - 设定的簇的数目.即k
4. RowCount - 数据对象的个数.即n

下面就是聚类方法中的代码:

private void Cluster(){int tmpclass = 0;double tmpClusDis = 0, tmpClusMinDis = 0;//清除每一个簇里原来的项for (int i = 0; i < ClassNum; i++){ClusterAssem[i].Clear();}//进行欧几里德距离计算并聚类for (int i = 0; i < RowCount - 1; i++){tmpClusMinDis = vurMax;for (int j = 0; j < ClassNum; j++){tmpClusDis = 0;//这里是取出每个维度的数据进行加和for (int k = 3; k < 7; k++){tmpClusDis += Math.Pow((System.Convert.ToDouble(XlsDataSh.Items[i].SubItems[k].Text) - CenterArrayParams[j, k - 3]), 2);}if (tmpClusDis < tmpClusMinDis){tmpclass = j;tmpClusMinDis = tmpClusDis;}}ClusterAssem[tmpclass].Add(i);}//重新初始化if (ClusterAssem[0].Count == 0 || ClusterAssem[1].Count == 0 || ClusterAssem[2].Count == 0 || ClusterAssem[3].Count == 0 || ClusterAssem[4].Count == 0){InitCenter();//重新初始化中心的方法.Cluster();}}

3.重新生成每个簇的中心

解释:
ClusterAssem - 存储每一个簇中包含的数据对象ArrayList
RenewCenterArrayParams - 存储每个簇中心的各个维度的ArrayList

private void RenewCenter() {double tmpSameDis = 0;for (int i = 0; i < ClassNum; i++) {for (int k = 3; k < 7; k++){tmpSameDis = 0;//遍历每个簇的点,求出中心点foreach (object n in ClusterAssem[i]) {tmpSameDis += System.Convert.ToDouble(XlsDataSh.Items[System.Convert.ToInt16(n)].SubItems[k].Text);}RenewCenterArrayParams[i, k - 3] = (tmpSameDis * 1.0 / (ClusterAssem[i].Count+1));}}}

4.计算结束的标记

结束标志的意图就是当中心不再发生变化或小于一个阈值的时候就停止算法的进行了.
解释:
1. BalEndFlag:用于存储前一次的中心加和用于和本次进行比对

private Boolean CalEndFlag() {double tmpDifferDis = 0, tmpSameDis = 0;for (int i = 0; i < ClassNum; i++) {tmpSameDis = 0;for (int j = 0; j < 4; j++) {tmpSameDis += Math.Pow((RenewCenterArrayParams[i, j] - CenterArrayParams[i, j]),2);}tmpDifferDis += Math.Pow(tmpSameDis,1.0/2);}//判断中心点和前一次的偏移if ((BalEndFlag - tmpDifferDis) <= EndFlag) return false;else {//算法没有结束,所以将新的中心赋给用于计算的ArrayListfor (int i = 0; i < ClassNum; i++) {for (int j = 0; j < 4; j++) {CenterArrayParams[i, j] = RenewCenterArrayParams[i, j];}}BalEndFlag = tmpDifferDis;tmpDifferDis = 0;return true;}}

结果展示

下面就是我做的基于K—Means的自动聚类评分系统的界面.首先我们先看看有监督下的聚类是否符合预期,如下图所示:

我们通过上图的红色框中可以看出这个聚类的结果和我们的预期是十分的符合的.下面就是我通过随机的生成方法生成的数据,来观察K-Means算法在无监督下的运行结果.如下图所示:

以上就是本次探究的最终成果展示.

K—Means的收敛性

K-Means算法一定是收敛的,否则就会陷入一直寻找新的”质心”而没有最终的结果了.具体的证明步骤较为复杂.通过参考一些文章(会在下文中参考中标出)涉及到了E-M算法.将一个聚类问题转化为一个最大似然估计问题可证明K-Means是E-M算法的一个特例.在E-M算法下,求得的参数一定是收敛的.在K-Means算法中目标是使损失函数最小,所以在E-step时,找到一个最逼近目标的函数,在M-step时,固定这个函数(数据对象的分配),更新均值(簇的中心),所以最后一定会收敛了.

基础K-Means算法的优化

由于K-Means是非常成熟的算法,所以有很多先辈们改良了这个算法,在这里仅仅只是介绍在各个方面有哪些能够参考改进的方法.
* 通过上文,我们可以知道.K-Means算法容易受到离群值的干扰.所以我们可以通过预处理比如「LOF算法」来先检测出离群点.单独处理这部分点.
* K-Means的k值在没有指定的时候是很难选择的,这个时候,可以通过「k-Means算法的k值自适应优化方法」
* 聚类的中心的选择.由于本文是随机选择初始的k个点,但是这是不合理的,应该是选择数据中距离尽可能远的K个点,这里也有一个算法「Canopy算法」
* 现在有许多改进了的K-Means的算法,比较出名的有「K-means++」「ISODATA」「Kernel K-means」等,在后面的文章中我会进行分享.

参考

1.「K-Means算法的收敛性和如何快速收敛超大的KMeans? - 大数据躺过的坑 - 博客园」(传送门)(http://www.cnblogs.com/zlslch/p/6965209.html?utm_source=itdadao&utm_medium=referral)
2.「请问如何用数学方法证明K-means是EM算法的特例?」(传送门)
https://www.zhihu.com/question/49972233?sort=created

标签: 算法, C#, 机器学习

C#下实现的基础K-MEANS多维聚类相关推荐

  1. 为了联盟还是为了部落 | K means

    1. 问题 人类有个很有趣的现象,一群人在一起,过一段时间就会自发的形成一个个的小团体.好像我们很擅长寻找和自己气质接近的同类.其实不只是人类,数据也有类似情况,这就是聚类(Clustering)的意 ...

  2. kmeans改进 matlab,基于距离函数的改进k―means 算法

    摘要:聚类算法在自然科学和和社会科学中都有很普遍的应用,而K-means算法是聚类算法中经典的划分方法之一.但如果数据集内相邻的簇之间离散度相差较大,或者是属性分布区间相差较大,则算法的聚类效果十分有 ...

  3. K means 图片压缩

    k-means的基本原理较为清晰,这里不多赘述,本次博客主要通过基础的k means算法进行图像的压缩处理. 原理分析 在彩色图像中,每个像素的大小为3字节(RGB),可以表示的颜色总数为256 * ...

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

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

  5. 文献记录(part89)--I-k-means-+:An iterative clustering algorithm based on an enhanced k -means

    学习笔记,仅供参考,有错必究 关键词:k均值:解决方案改进:准确的k均值:迭代改进 I-k-means-+:An iterative clustering algorithm based on an ...

  6. 机器学习基础|K折交叉验证与超参数搜索

    文章目录 交叉验证 交叉验证的概念 K的取值 为什么要用K折交叉验证 Sklearn交叉验证API 超参数搜索 超参数的概念 超参数搜索的概念 超参数搜索的原理 Sklearn超参数搜索API 实例 ...

  7. k均值聚类算法(K Means)及其实战案例

    算法说明 K均值聚类算法其实就是根据距离来看属性,近朱者赤近墨者黑.其中K表示要聚类的数量,就是说样本要被划分成几个类别.而均值则是因为需要求得每个类别的中心点,比如一维样本的中心点一般就是求这些样本 ...

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

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

  9. Linux下libxml2编程基础

    Linux下libxml2编程基础 一.libxml2的简介 xml是一个实现读.创建.以及操作xml数据功能的C语言库.并且支持XPATH查询,以及部分的支持XSLT转换等的功能. libxml2的 ...

最新文章

  1. 互联网金融如何助力实体经济?
  2. android studio安装中出现Failed to install Intel HAXM错误的解决方法
  3. Linux内存描述之概述--Linux内存管理(一)
  4. 下载 | 新版Java开发手册有哪些亮点?
  5. Windows系统程序设计之结构化异常处理
  6. 1个已知CVE,7步,找到一个高质量RCE并获奖金
  7. iOS11 tableview左滑到底禁用删除
  8. hexo笔记十五:next主题添加网易云外链
  9. android 主流分辨率是多少,Android程序开发设计主流屏幕分辨率介绍
  10. IllustratorCS6-桌面排版与插画绘制-01-使用散点画笔绘制璀璨星云
  11. 用css设置多段背景色
  12. flex TLF 文本流编辑器
  13. 学习记录657@python计算股价的回撤与收盘价回撤率组合图实现
  14. 用matlab画脑图,思维导图怎么画,画出一副好看的流程图方法是什么
  15. dell服务器510系统,dellr510服务器上安系统.docx
  16. 计算机网络——已知 IP 地址,求解子网的网络地址
  17. Typescript 笔记
  18. SAP中常用到的增强
  19. 全球与中国电子设计自动化软件市场深度研究分析报告(2021)
  20. win8u盘启动linux系统,在Mac系统下制作Windows启动U盘(失败案例)

热门文章

  1. 记录一次conda环境报错的解决ImportError:: Library not loaded: @rpath/libffi.7.dylib
  2. 消消乐实现下坠_手把手教你如何实现iOS消消乐小游戏Demo
  3. mac下php的坑,MAC下安装laravel时遇到的坑
  4. servlet-cookie实现向客户端写cookie信息
  5. 大学计算机基础网络配置实验报告答案,大学计算机基础实验报告2.doc
  6. python内嵌函数和闭包与java 匿名内部类_Lambda表达式与匿名内部类的联系和区别...
  7. 2_python基础—格式化符号(输入、输出、转义、结束)
  8. 动态二维数组外圈元素值的和_C语言 | 用指向元素的指针变量输出二维数组元素的值...
  9. 【pytest】Hook 方法之 pytest_addoption :注册命令行参数
  10. python中的一些基础