Python机器学习算法之k均值聚类(k-means)


Posted in Python onFebruary 23, 2018

一开始的目的是学习十大挖掘算法(机器学习算法),并用编码实现一遍,但越往后学习,越往后实现编码,越发现自己的编码水平低下,学习能力低。这一个k-means算法用Python实现竟用了三天时间,可见编码水平之低,而且在编码的过程中看了别人的编码,才发现自己对numpy认识和运用的不足,在自己的代码中有很多可以优化的地方,比如求均值的地方可以用mean直接对数组求均值,再比如去最小值的下标,我用的是argsort排序再取列表第一个,但是有argmin可以直接用啊。下面的代码中这些可以优化的并没有改,这么做的原因是希望做到抛砖引玉,欢迎大家丢玉,如果能给出优化方法就更好了

一.k-means算法

人以类聚,物以群分,k-means聚类算法就是体现。数学公式不要,直接用白话描述的步骤就是:

1.随机选取k个质心(k值取决于你想聚成几类)
2.计算样本到质心的距离,距离质心距离近的归为一类,分为k类
3.求出分类后的每类的新质心
4.判断新旧质心是否相同,如果相同就代表已经聚类成功,如果没有就循环2-3直到相同

用程序的语言描述就是:

1.输入样本
2.随机去k个质心
3.重复下面过程知道算法收敛:

计算样本到质心距离(欧几里得距离)
样本距离哪个质心近,就记为那一类
计算每个类别的新质心(平均值)

二.需求分析

数据来源:从国际统计局down的数据,数据为城乡居民家庭人均收入及恩格尔系数(点击这里下载)

Python机器学习算法之k均值聚类(k-means)

数据描述:

1.横轴:城镇居民家庭人均可支配收入和农村居民家庭人均纯收入,
2.纵轴:1996-2012年。
3.数据为年度数据

需求说明:我想把这数据做个聚类分析,看人民的收入大概经历几个阶段(感觉我好高大上啊)

需求分析:

1.由于样本数据有限,就两列,用k-means聚类有很大的准确性
2.用文本的形式导入数据,结果输出聚类后的质心,这样就能看出人民的收入经历了哪几个阶段

三.Python实现

引入numpy模块,借用其中的一些方法进行数据处理,上代码:

# -*- coding=utf-8 -*-

"""
authon:xuwf
created:2017-02-07
purpose:实现k-means算法
"""

import numpy as np
import random

'''装载数据'''
def load():
 data=np.loadtxt('data\k-means.csv',delimiter=',')
 return data

'''计算距离'''
def calcDis(data,clu,k):
 clalist=[] #存放计算距离后的list
 data=data.tolist() #转化为列表
 clu=clu.tolist()
 for i in range(len(data)):
  clalist.append([])
  for j in range(k):
   dist=round(((data[i][1]-clu[j][0])**2+(data[i][2]-clu[j][1])**2)*0.05,1)
   clalist[i].append(dist)
 clalist=np.array(clalist) #转化为数组
 return clalist

'''分组'''
def group(data,clalist,k):
 grouplist=[] #存放分组后的集群
 claList=clalist.tolist()
 data=data.tolist()
 for i in range(k):
  #确定要分组的个数,以空列表的形式,方便下面进行数据的插入
  grouplist.append([])
 for j in range(len(clalist)):
  sortNum=np.argsort(clalist[j])
  grouplist[sortNum[0]].append(data[j][1:])
 grouplist=np.array(grouplist)
 return grouplist

'''计算质心'''
def calcCen(data,grouplist,k):
 clunew=[]
 data=data.tolist()
 grouplist=grouplist.tolist()
 templist=[]
 #templist=np.array(templist)
 for i in range(k):
  #计算每个组的新质心
  sumx=0
  sumy=0
  for j in range(len(grouplist[i])):
   sumx+=grouplist[i][j][0]
   sumy+=grouplist[i][j][1]
  clunew.append([round(sumx/len(grouplist[i]),1),round(sumy/len(grouplist[i]),1)])
 clunew=np.array(clunew)
 #clunew=np.mean(grouplist,axis=1)
 return clunew

'''优化质心'''
def classify(data,clu,k):
 clalist=calcDis(data,clu,k) #计算样本到质心的距离
 grouplist=group(data,clalist,k) #分组
 for i in range(k):
  #替换空值
  if grouplist[i]==[]:
   grouplist[i]=[4838.9,1926.1]
 clunew=calcCen(data,grouplist,k)
 sse=clunew-clu
 #print "the clu is :%r\nthe group is :%r\nthe clunew is :%r\nthe sse is :%r" %(clu,grouplist,clunew,sse)
 return sse,clunew,data,k 

if __name__=='__main__':
 k=3 #给出要分类的个数的k值
 data=load() #装载数据
 clu=random.sample(data[:,1:].tolist(),k) #随机取质心
 clu=np.array(clu)
 sse,clunew,data,k=classify(data,clu,k)
 while np.any(sse!=0):
  sse,clunew,data,k=classify(data,clunew,k)
 clunew=np.sort(clunew,axis=0)
 print "the best cluster is %r" %clunew

四.测试

直接运行程序就可以,k值可以自己设置,会发现k=3的时候结果数据是最稳定的,这里我就不贴图了
需要注意的是上面的代码里面主函数里的数据结构都是array,但是在每个小函数里就有可能转化成了list,主要原因是需要进行array的一下方法进行计算,而转化为list的原因是需要向数组中插入数据,但是array做不到啊(至少我没找到怎么做)。于是这里就出现了一个问题,那就是数据结构混乱,到最后我调试了半天,干脆将主函数的数据结构都转化成array,在小函数中输入的array,输出的时候也转化成了array,这样就清晰多了

五.算法分析

单看这个算法还是较好理解的,但是算法的目的是聚类,那就要考虑到聚类的准确性,这里聚类的准确性取决于k值、初始质心和距离的计算方式。

  • k值就要看个人经验和多次试验了,算法结果在哪个k值的时候更稳定就证明这个分类更加具有可信度,其中算法结果的稳定也取决于初始质心的选择
  • 初始质心一般都是随机选取的,怎么更准确的选择初始质心呢?有种较难实现的方法是将样本中所有点组合起来都取一遍,然后计算算法收敛后的所有质心到样本的距离之和,哪个距离最小,哪个的聚类就最为成功,相对应的初始质心就选取的最为准确。但是这种方法有很大的计算量,如果样本很大,维度很多,那就是让电脑干到死的节奏
  • 距离的计算方式取决于样本的特征,有很多的选择,入欧式距离,夹角余弦距离,曼哈顿距离等,具体的数据特性用具体的距离计算方式

六.项目评测

1.项目总结数据源的数据很干净,不需要进行过多的数据清洗和数据降噪,数据预处理的工作成本接近为0。需求基本实现
2.还能做什么:可以用计算最小距离之和的方法求出最佳k值,这样就可以得到稳定的收入阶梯;可以引入画图模块,将数据结果进行数据可视化,显得更加直观;如果可能应该引入更多的维度或更多的数据,这样得到的聚类才更有说服力。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python统计文本文件内单词数量的方法
May 30 Python
python检测是文件还是目录的方法
Jul 03 Python
Python使用SocketServer模块编写基本服务器程序的教程
Jul 12 Python
Python 异常处理的实例详解
Sep 11 Python
python3实现windows下同名进程监控
Jun 21 Python
使用Python检测文章抄袭及去重算法原理解析
Jun 14 Python
PyQt5 窗口切换与自定义对话框的实例
Jun 20 Python
Python编程中类与类的关系详解
Aug 08 Python
selenium+Chrome滑动验证码破解二(某某网站)
Dec 17 Python
如何基于Python Matplotlib实现网格动画
Jul 20 Python
python 如何用urllib与服务端交互(发送和接收数据)
Mar 04 Python
Django使用echarts进行可视化展示的实践
Jun 10 Python
python3调用R的示例代码
Feb 23 #Python
python中kmeans聚类实现代码
Feb 23 #Python
python实现SOM算法
Feb 23 #Python
python实现k-means聚类算法
Feb 23 #Python
python写一个md5解密器示例
Feb 23 #Python
Python机器学习之K-Means聚类实现详解
Feb 22 #Python
python实现远程通过网络邮件控制计算机重启或关机
Feb 22 #Python
You might like
php多重接口的实现方法
2015/06/20 PHP
Yii控制器中filter过滤器用法分析
2016/07/15 PHP
php无限级分类实现评论及回复功能
2019/02/18 PHP
javascript 表单的友好用户体现
2009/01/07 Javascript
jquery 批量上传图片实现代码
2010/01/28 Javascript
jquery validate使用攻略 第四步
2010/07/01 Javascript
jquery插件珍藏(图片局部放大/信息提示框)
2013/01/08 Javascript
js屏蔽鼠标键盘(右键/Ctrl+N/Shift+F10/F11/F5刷新/退格键)
2013/01/24 Javascript
Javascript MVC框架Backbone.js详解
2014/09/18 Javascript
Web表单提交之disabled问题js解决方法
2015/01/13 Javascript
如何使用jQuery技术开发ios风格的页面导航菜单
2015/07/29 Javascript
jquery实现鼠标滑过显示二级下拉菜单效果
2015/08/24 Javascript
JS模拟简易滚动条效果代码(附demo源码)
2016/04/05 Javascript
jQuery实现div横向拖拽排序的简单实例
2016/07/13 Javascript
JavaScript获取当前时间向前推三个月的方法示例
2017/02/04 Javascript
JavaScript之filter_动力节点Java学院整理
2017/06/28 Javascript
jQuery实现导航栏头部菜单项点击后变换颜色的方法
2017/07/19 jQuery
JS判断微信扫码的方法
2017/08/07 Javascript
React-Native 组件之 Modal的使用详解
2017/08/08 Javascript
jQuery Easyui Treegrid实现显示checkbox功能
2017/08/08 jQuery
快速处理vue渲染前的显示问题
2018/03/05 Javascript
nuxt.js中间件实现拦截权限判断的方法
2018/11/21 Javascript
JS实现的小火箭发射动画效果示例
2018/12/08 Javascript
简单通过settimeout看javascript的运行机制
2019/05/10 Javascript
详解微信小程序开发之formId使用(模板消息)
2019/08/27 Javascript
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
Python smallseg分词用法实例分析
2015/05/28 Python
Python实现邮件的批量发送的示例代码
2018/01/23 Python
关于ZeroMQ 三种模式python3实现方式
2019/12/23 Python
探讨HTML5移动开发的几大特性(必看)
2015/12/30 HTML / CSS
美国一家专业的太阳镜网上零售商:Solstice太阳镜
2016/07/25 全球购物
市场部规章制度
2014/01/24 职场文书
2014年党员学习“三严三实”思想汇报
2014/09/15 职场文书
个人作风建设总结
2014/10/23 职场文书
劳模事迹材料范文
2014/12/24 职场文书
大学生青年志愿者活动总结
2015/05/06 职场文书