机器学习:Python实现聚类算法(一)之K-Means
1.简介
K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一。K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果。
2. 算法大致流程为:
1)随机选取k个点作为种子点(这k个点不一定属于数据集)
2)分别计算每个数据点到k个种子点的距离,离哪个种子点最近,就属于哪类
3)重新计算k个种子点的坐标(简单常用的方法是求坐标值的平均值作为新的坐标值)
4)重复2、3步,直到种子点坐标不变或者循环次数完成
3.完整计算过程
1)设置实验数据
import numpy as np import matplotlib.pyplot as plt ##样本数据(Xi,Yi),需要转换成数组(列表)形式 Xn=np.array([2,3,1.9,2.5,4]) Yn=np.array([5,4.8,4,1.8,2.2]) ##种子 Xk=np.array([3.3,3.0]) Yk=np.array([5.7,3.2]) #标识符号 sign_n = ['A','B','C','D','E'] sign_k = ['k1','k2'] def draw_point(Xk,Yk): #画样本点 plt.figure(figsize=(5,4)) plt.scatter(Xn,Yn,color="green",label="数据",linewidth=1) plt.scatter(Xk,Yk,color="red",label="种子",linewidth=1) plt.xticks(range(1,6)) plt.xlim([1,5]) plt.ylim([1,6]) plt.legend() for i in range(len(Xn)): plt.text(Xn[i],Yn[i],sign_n[i]) for i in range(len(Xk)): plt.text(Xk[i],Yk[i],sign_k[i]) plt.show() if __name__ == "__main__": ##种子 Xk=np.array([3.3,3.0]) Yk=np.array([5.7,3.2]) draw_point(Xk,Yk)
运行之后,效果如下图所示:
在图中,ABCDE五个点是待分类点,k1、k2是两个种子点。
2)计算ABCDE五个点到k1、k2的距离,离哪个点近,就属于哪个点,进行初步分类。核心代码如下:
def start_class(Xk,Yk): ##数据点分类 cls_dict = {} ##离哪个分类点最近,属于哪个分类 for i in range(len(Xn)): temp = [] for j in range(len(Xk)): d1 = np.sqrt((Xn[i]-Xk[j])*(Xn[i]-Xk[j])+(Yn[i]-Yk[j])*(Yn[i]-Yk[j])) temp.append(d1) min_dis=np.min(temp) min_inx = temp.index(min_dis) cls_dict[sign_n[i]]=sign_k[min_inx] #print(cls_dict) return cls_dict def draw_point(Xk,Yk,cls_dict): #画样本点 plt.figure(figsize=(5,4)) plt.scatter(Xn,Yn,color="green",label="数据",linewidth=1) plt.scatter(Xk,Yk,color="red",label="分类",linewidth=1) plt.xticks(range(1,6)) plt.xlim([1,5]) plt.ylim([1,6]) plt.legend() for i in range(len(Xn)): plt.text(Xn[i],Yn[i],sign_n[i]+":"+cls_dict[sign_n[i]]) for i in range(len(Xk)): plt.text(Xk[i],Yk[i],sign_k[i]) plt.show() if __name__ == "__main__": ##种子 Xk=np.array([3.3,3.0]) Yk=np.array([5.7,3.2]) cls_dict =start_class(Xk,Yk) draw_point(Xk,Yk,cls_dict)
结果如图:
A、B属于k1,C、D、E属于k2
3)重新计算k1、k2的坐标。这里使用简单的坐标的平均值,使用其他算法也可以。主要代码:
##重新计算分类的坐标点 def recal_class_point(Xk,Yk,cls_dict): num_k1 = 0 #属于k1的数据点的个数 num_k2 = 0 #属于k2的数据点的个数 x1 =0 #属于k1的x坐标和 y1 =0 #属于k1的y坐标和 x2 =0 #属于k2的x坐标和 y2 =0 #属于k2的y坐标和 ##循环读取已经分类的数据 for d in cls_dict: ##读取d的类别 kk = cls_dict[d] if kk == 'k1': #读取d在数据集中的索引 idx = sign_n.index(d) ##累加x值 x1 += Xn[idx] ##累加y值 y1 += Yn[idx] ##累加分类个数 num_k1 += 1 else : #读取d在数据集中的索引 idx = sign_n.index(d) ##累加x值 x2 += Xn[idx] ##累加y值 y2 += Yn[idx] ##累加分类个数 num_k2 += 1 ##求平均值获取新的分类坐标点 k1_new_x = x1/num_k1 #新的k1的x坐标 k1_new_y = y1/num_k1 #新的k1的y坐标 k2_new_x = x2/num_k2 #新的k2的x坐标 k2_new_y = y2/num_k2 #新的k2的y坐标 ##新的分类数组 Xk=np.array([k1_new_x,k2_new_x]) Yk=np.array([k1_new_y,k2_new_y]) return Xk,Yk
结果如图:
4)重复2、3步,直到最终分类完毕。下面是完整的示例代码:
import numpy as np import matplotlib.pyplot as plt ##样本数据(Xi,Yi),需要转换成数组(列表)形式 Xn=np.array([2,3,1.9,2.5,4]) Yn=np.array([5,4.8,4,1.8,2.2]) #标识符号 sign_n = ['A','B','C','D','E'] sign_k = ['k1','k2'] def start_class(Xk,Yk): ##数据点分类 cls_dict = {} ##离哪个分类点最近,属于哪个分类 for i in range(len(Xn)): temp = [] for j in range(len(Xk)): d1 = np.sqrt((Xn[i]-Xk[j])*(Xn[i]-Xk[j])+(Yn[i]-Yk[j])*(Yn[i]-Yk[j])) temp.append(d1) min_dis=np.min(temp) min_inx = temp.index(min_dis) cls_dict[sign_n[i]]=sign_k[min_inx] #print(cls_dict) return cls_dict ##重新计算分类的坐标点 def recal_class_point(Xk,Yk,cls_dict): num_k1 = 0 #属于k1的数据点的个数 num_k2 = 0 #属于k2的数据点的个数 x1 =0 #属于k1的x坐标和 y1 =0 #属于k1的y坐标和 x2 =0 #属于k2的x坐标和 y2 =0 #属于k2的y坐标和 ##循环读取已经分类的数据 for d in cls_dict: ##读取d的类别 kk = cls_dict[d] if kk == 'k1': #读取d在数据集中的索引 idx = sign_n.index(d) ##累加x值 x1 += Xn[idx] ##累加y值 y1 += Yn[idx] ##累加分类个数 num_k1 += 1 else : #读取d在数据集中的索引 idx = sign_n.index(d) ##累加x值 x2 += Xn[idx] ##累加y值 y2 += Yn[idx] ##累加分类个数 num_k2 += 1 ##求平均值获取新的分类坐标点 k1_new_x = x1/num_k1 #新的k1的x坐标 k1_new_y = y1/num_k1 #新的k1的y坐标 k2_new_x = x2/num_k2 #新的k2的x坐标 k2_new_y = y2/num_k2 #新的k2的y坐标 ##新的分类数组 Xk=np.array([k1_new_x,k2_new_x]) Yk=np.array([k1_new_y,k2_new_y]) return Xk,Yk def draw_point(Xk,Yk,cls_dict): #画样本点 plt.figure(figsize=(5,4)) plt.scatter(Xn,Yn,color="green",label="数据",linewidth=1) plt.scatter(Xk,Yk,color="red",label="分类",linewidth=1) plt.xticks(range(1,6)) plt.xlim([1,5]) plt.ylim([1,6]) plt.legend() for i in range(len(Xn)): plt.text(Xn[i],Yn[i],sign_n[i]+":"+cls_dict[sign_n[i]]) for i in range(len(Xk)): plt.text(Xk[i],Yk[i],sign_k[i]) plt.show() if __name__ == "__main__": ##种子 Xk=np.array([3.3,3.0]) Yk=np.array([5.7,3.2]) ##循环3次结束 for i in range(3): cls_dict =start_class(Xk,Yk) Xk_new,Yk_new =recal_class_point(Xk,Yk,cls_dict) Xk=Xk_new Yk=Yk_new draw_point(Xk,Yk,cls_dict)
最终分类结果:
由上图可以看出,C点最终是属于k1类,而不是开始的k2.
4.K-Means的不足
K-Means算法的不足,都是由初始值引起的:
1)初始分类数目k值很难估计,不确定应该分成多少类才最合适(ISODATA算法通过类的自动合并和分裂,得到较为合理的类型数目k。这里不讲这个算法)
2)不同的随机种子会得到完全不同的结果(K-Means++算法可以用来解决这个问题,其可以有效地选择初始点)
5.K-Means++算法
算法流程如下:
1)在数据集中随机挑选1个点作为种子点
##随机挑选一个数据点作为种子点 def select_seed(Xn): idx = np.random.choice(range(len(Xn))) return idx
2)计算剩数据点到这个点的距离d(x),并且加入到列表
##计算数据点到种子点的距离 def cal_dis(Xn,Yn,idx): dis_list = [] for i in range(len(Xn)): d = np.sqrt((Xn[i]-Xn[idx])**2+(Yn[i]-Yn[idx])**2) dis_list.append(d) return dis_list
3)再取一个随机值。这次的选择思路是:先取一个能落在上步计算的距离列表求和后(sum(dis_list))的随机值rom,然后用rom -= d(x),直到rom<=0,此时的点就是下一个“种子点”
##随机挑选另外的种子点 def select_seed_other(Xn,Yn,dis_list): d_sum = sum(dis_list) rom = d_sum * np.random.random() idx = 0 for i in range(len(Xn)): rom -= dis_list[i] if rom > 0 : continue else : idx = i return idx
4)重复第2步和第3步,直到选出k个种子
##选取所有种子点 def select_seed_all(seed_count): ##种子点 Xk = [] ##种子点x轴列表 Yk = [] ##种子点y轴列表 idx = 0 ##选取的种子点的索引 dis_list = [] ##距离列表 ##选取种子点 #因为实验数据少,有一定的几率选到同一个数据,所以加一个判断 idx_list = [] flag = True for i in range(seed_count): if i == 0: idx = select_seed(Xn) dis_list = cal_dis(Xn,Yn,idx) Xk.append(Xn[idx]) Yk.append(Yn[idx]) idx_list.append(idx) else : while flag: idx = select_seed_other(Xn,Yn,dis_list) if idx not in idx_list: flag = False else : continue dis_list = cal_dis(Xn,Yn,idx) Xk.append(Xn[idx]) Yk.append(Yn[idx]) idx_list.append(idx) ##列表转成数组 Xk=np.array(Xk) Yk=np.array(Yk) return Xk,Yk
5)进行标准的K-Means算法。下面完整代码
import numpy as np import matplotlib.pyplot as plt ##样本数据(Xi,Yi),需要转换成数组(列表)形式 Xn=np.array([2,3,1.9,2.5,4]) Yn=np.array([5,4.8,4,1.8,2.2]) #标识符号 sign_n = ['A','B','C','D','E'] sign_k = ['k1','k2'] ##随机挑选一个数据点作为种子点 def select_seed(Xn): idx = np.random.choice(range(len(Xn))) return idx ##计算数据点到种子点的距离 def cal_dis(Xn,Yn,idx): dis_list = [] for i in range(len(Xn)): d = np.sqrt((Xn[i]-Xn[idx])**2+(Yn[i]-Yn[idx])**2) dis_list.append(d) return dis_list ##随机挑选另外的种子点 def select_seed_other(Xn,Yn,dis_list): d_sum = sum(dis_list) rom = d_sum * np.random.random() idx = 0 for i in range(len(Xn)): rom -= dis_list[i] if rom > 0 : continue else : idx = i return idx ##选取所有种子点 def select_seed_all(seed_count): ##种子点 Xk = [] ##种子点x轴列表 Yk = [] ##种子点y轴列表 idx = 0 ##选取的种子点的索引 dis_list = [] ##距离列表 ##选取种子点 #因为实验数据少,有一定的几率选到同一个数据,所以加一个判断 idx_list = [] flag = True for i in range(seed_count): if i == 0: idx = select_seed(Xn) dis_list = cal_dis(Xn,Yn,idx) Xk.append(Xn[idx]) Yk.append(Yn[idx]) idx_list.append(idx) else : while flag: idx = select_seed_other(Xn,Yn,dis_list) if idx not in idx_list: flag = False else : continue dis_list = cal_dis(Xn,Yn,idx) Xk.append(Xn[idx]) Yk.append(Yn[idx]) idx_list.append(idx) ##列表转成数组 Xk=np.array(Xk) Yk=np.array(Yk) return Xk,Yk def start_class(Xk,Yk): ##数据点分类 cls_dict = {} ##离哪个分类点最近,属于哪个分类 for i in range(len(Xn)): temp = [] for j in range(len(Xk)): d1 = np.sqrt((Xn[i]-Xk[j])*(Xn[i]-Xk[j])+(Yn[i]-Yk[j])*(Yn[i]-Yk[j])) temp.append(d1) min_dis=np.min(temp) min_inx = temp.index(min_dis) cls_dict[sign_n[i]]=sign_k[min_inx] #print(cls_dict) return cls_dict ##重新计算分类的坐标点 def recal_class_point(Xk,Yk,cls_dict): num_k1 = 0 #属于k1的数据点的个数 num_k2 = 0 #属于k2的数据点的个数 x1 =0 #属于k1的x坐标和 y1 =0 #属于k1的y坐标和 x2 =0 #属于k2的x坐标和 y2 =0 #属于k2的y坐标和 ##循环读取已经分类的数据 for d in cls_dict: ##读取d的类别 kk = cls_dict[d] if kk == 'k1': #读取d在数据集中的索引 idx = sign_n.index(d) ##累加x值 x1 += Xn[idx] ##累加y值 y1 += Yn[idx] ##累加分类个数 num_k1 += 1 else : #读取d在数据集中的索引 idx = sign_n.index(d) ##累加x值 x2 += Xn[idx] ##累加y值 y2 += Yn[idx] ##累加分类个数 num_k2 += 1 ##求平均值获取新的分类坐标点 k1_new_x = x1/num_k1 #新的k1的x坐标 k1_new_y = y1/num_k1 #新的k1的y坐标 k2_new_x = x2/num_k2 #新的k2的x坐标 k2_new_y = y2/num_k2 #新的k2的y坐标 ##新的分类数组 Xk=np.array([k1_new_x,k2_new_x]) Yk=np.array([k1_new_y,k2_new_y]) return Xk,Yk def draw_point(Xk,Yk,cls_dict): #画样本点 plt.figure(figsize=(5,4)) plt.scatter(Xn,Yn,color="green",label="数据",linewidth=1) plt.scatter(Xk,Yk,color="red",label="分类",linewidth=1) plt.xticks(range(1,6)) plt.xlim([1,5]) plt.ylim([1,6]) plt.legend() for i in range(len(Xn)): plt.text(Xn[i],Yn[i],sign_n[i]+":"+cls_dict[sign_n[i]]) for i in range(len(Xk)): plt.text(Xk[i],Yk[i],sign_k[i]) plt.show() def draw_point_all_seed(Xk,Yk): #画样本点 plt.figure(figsize=(5,4)) plt.scatter(Xn,Yn,color="green",label="数据",linewidth=1) plt.scatter(Xk,Yk,color="red",label="分类",linewidth=1) plt.xticks(range(1,6)) plt.xlim([1,5]) plt.ylim([1,6]) plt.legend() for i in range(len(Xn)): plt.text(Xn[i],Yn[i],sign_n[i]) plt.show() if __name__ == "__main__": ##选取2个种子点 Xk,Yk = select_seed_all(2) ##查看种子点 draw_point_all_seed(Xk,Yk) ##循环三次进行分类 for i in range(3): cls_dict =start_class(Xk,Yk) Xk_new,Yk_new =recal_class_point(Xk,Yk,cls_dict) Xk=Xk_new Yk=Yk_new draw_point(Xk,Yk,cls_dict)
如图所示,选择了A、E两点作为种子点。
最终的结果。
补充说明:因为数据量太少,在选取所有种子函数的while阶段有可能陷入死循环,所以需要关闭代码重新运行才可以出结果。
机器学习:Python实现聚类算法(一)之K-Means的更多相关文章
- Python聚类算法之基本K均值实例详解
Python聚类算法之基本K均值实例详解 本文实例讲述了Python聚类算法之基本K均值运算技巧.分享给大家供大家参考,具体如下: 基本K均值 :选择 K 个初始质心,其中 K 是用户指定的参数,即所 ...
- 机器学习六--K-means聚类算法
机器学习六--K-means聚类算法 想想常见的分类算法有决策树.Logistic回归.SVM.贝叶斯等.分类作为一种监督学习方法,要求必须事先明确知道各个类别的信息,并且断言所有待分类项都有一个类别 ...
- 机器学习:Python实现聚类算法(三)之总结
考虑到学习知识的顺序及效率问题,所以后续的几种聚类方法不再详细讲解原理,也不再写python实现的源代码,只介绍下算法的基本思路,使大家对每种算法有个直观的印象,从而可以更好的理解函数中参数的意义及作 ...
- 【Python机器学习实战】聚类算法(1)——K-Means聚类
实战部分主要针对某一具体算法对其原理进行较为详细的介绍,然后进行简单地实现(可能对算法性能考虑欠缺),这一部分主要介绍一些常见的一些聚类算法. K-means聚类算法 0.聚类算法算法简介 聚类算法算 ...
- 机器学习:Python实现聚类算法(一)之AP算法
1.算法简介 AP(Affinity Propagation)通常被翻译为近邻传播算法或者亲和力传播算法,是在2007年的Science杂志上提出的一种新的聚类算法.AP算法的基本思想是将全部数据点都 ...
- 机器学习:Python实现聚类算法(二)之AP算法
1.算法简介 AP(Affinity Propagation)通常被翻译为近邻传播算法或者亲和力传播算法,是在2007年的Science杂志上提出的一种新的聚类算法.AP算法的基本思想是将全部数据点都 ...
- 【Python机器学习实战】聚类算法(2)——层次聚类(HAC)和DBSCAN
层次聚类和DBSCAN 前面说到K-means聚类算法,K-Means聚类是一种分散性聚类算法,本节主要是基于数据结构的聚类算法--层次聚类和基于密度的聚类算法--DBSCAN两种算法. 1.层次聚类 ...
- Mahout机器学习平台之聚类算法具体剖析(含实例分析)
第一部分: 学习Mahout必需要知道的资料查找技能: 学会查官方帮助文档: 解压用于安装文件(mahout-distribution-0.6.tar.gz),找到例如以下位置.我将该文件解压到win ...
- 机器学习:K-Means聚类算法
本文来自同步博客. 前面几篇文章介绍了回归或分类的几个算法,它们的共同点是训练数据包含了输出结果,要求算法能够通过训练数据掌握规律,用于预测新输入数据的输出值.因此,回归算法或分类算法被称之为监督学习 ...
- 机器学习中K-means聚类算法原理及C语言实现
本人以前主要focus在传统音频的软件开发,接触到的算法主要是音频信号处理相关的,如各种编解码算法和回声消除算法等.最近切到语音识别上,接触到的算法就变成了各种机器学习算法,如GMM等.K-means ...
随机推荐
- 用 config drive 配置网络 - 每天5分钟玩转 OpenStack(173)
上一节最后问了大家一个问题:如果 subnet 没有开 DHCP,会是怎样一个情况? 在其他条件不变的情况下,cloud-init 依然会完成那 3 个步骤,也就是说网卡还是会被配置成 dhcp 模式 ...
- Android完全退出activity
在Android中,如果想退出Android程序,一般都是调用finish().System.exit(0).android.os.Process.killProcess(android.os.Pro ...
- Influxdb1.2.2安装_Windows
一.文件准备 1.1 文件名称 influxdb-1.2.2_windows_amd64.zip 1.2 下载地址 https://portal.influxdata.com/downloads [注 ...
- 告别S! S! H!秒杀终端工具——FastLogin快捷登录
题记:自从接触到"跳板机"的概念后,一直就被烦不胜烦的机器名,ip地址,用户名,密码折腾的死去活来,心说能有个小精灵随时帮我输入那些重复的登录信息就好了.我见过最挫的方式就是用记事 ...
- C#对文件操作(基本的读写以及压缩和解压)
主要是针对单个文件进行读写操作和压缩操作:用到的主要C#类有FileStream.FileInfo.StreamWrite.StreamRead.GZipStream. 字符数组和字节数组的转换: ] ...
- C#调用WebService接口实现天气预报在web前端显示
本文使用web (C#)调用互联网上公开的WebServices接口: (http://www.webxml.com.cn/WebServices/WeatherWebService.asmx)来实现 ...
- Intellij Idea 用Maven 创建Hibernate 项目
第一步:创建maven项目 2. 3. 4.第三步保存之后进行下一步 到此点击finish maven项目创建成功,点击完成后会进行一系列jar包的下载 maven 仓库的默认存储位置 第二步:连接数 ...
- python_Tornado_web_框架_分页
如何实现web_框架_分页? -- 思考什么是xss跨站攻击? --别人把js代码提交到后台,然后从后台返回数据的时候,别人上传的js变成html中的代码, 就会插入别人的代码,带来极大的信息泄露的风 ...
- org.gradle.api.internal.tasks.DefaultTaskInputs$TaskInputUnionFileCollection cannot be cast to org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection
转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6709758.html Android Studio导入项目报错: org.gradle.api.inter ...
- VUE进阶(路由等)
初级教程:http://www.cnblogs.com/dmcl/p/6137469.html VUE进阶 自定义指令 http://cn.vuejs.org/v2/guide/custom-dire ...