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 matplotlib画图实例代码分享
Dec 27 Python
Python实现基于POS算法的区块链
Aug 07 Python
tensorflow实现简单逻辑回归
Sep 07 Python
只需7行Python代码玩转微信自动聊天
Jan 27 Python
python网络编程之多线程同时接受和发送
Sep 03 Python
Python3 翻转二叉树的实现
Sep 30 Python
python代码实现TSNE降维数据可视化教程
Feb 28 Python
Python unittest单元测试框架实现参数化
Apr 29 Python
如何理解python中数字列表
May 29 Python
浅析Python 字符编码与文件处理
Sep 24 Python
Python之字符串的遍历的4种方式
Dec 08 Python
Python抖音快手代码舞(字符舞)的实现方法
Feb 07 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
递归列出所有文件和目录
2006/10/09 PHP
php下用GD生成生成缩略图的两个选择和区别
2007/04/17 PHP
PHP 危险函数全解析
2009/09/09 PHP
thinkphp5 URL和路由的功能详解与实例
2017/12/26 PHP
CI框架(CodeIgniter)操作redis的方法详解
2018/01/25 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
2019/12/18 PHP
前台js改变Session的值(用ajax实现)
2012/12/28 Javascript
JS实现带圆弧背景渐变效果的导航菜单代码
2015/10/13 Javascript
JavaScript实现简单的tab选项卡切换
2016/01/05 Javascript
jQuery+css实现的时钟效果(兼容各浏览器)
2016/01/27 Javascript
JavaScript中apply方法的应用技巧小结
2016/09/29 Javascript
js拼接html字符串的注意事项
2016/10/13 Javascript
微信开发 JS-SDK 6.0.2 经常遇到问题总结
2016/12/08 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
功能完善的小程序日历组件的实现
2020/03/31 Javascript
VUE中V-IF条件判断改变元素的样式操作
2020/08/09 Javascript
[04:04]显微镜下的DOTA2第六期——电影级别的华丽团战
2014/06/20 DOTA
pycharm 使用心得(七)一些实用功能介绍
2014/06/06 Python
使用pycharm生成代码模板的实例
2018/05/23 Python
Python元组常见操作示例
2019/02/19 Python
Django REST framework 分页的实现代码
2019/06/19 Python
Python如何使用OS模块调用cmd
2020/02/27 Python
Python之Sklearn使用入门教程
2021/02/19 Python
Lenox官网:精美的瓷器&独特的礼品
2017/02/12 全球购物
Artist Guitars新西兰:乐器在线商店
2017/09/17 全球购物
如何高效率的查找一个月以内的数据
2012/04/15 面试题
经销商培训邀请函
2014/01/21 职场文书
本科毕业生专业自荐书范文
2014/02/05 职场文书
纪检监察建议书
2014/05/19 职场文书
2014应届本科生自我评价
2014/09/13 职场文书
一年级班主任工作总结2014
2014/11/08 职场文书
2015年度个人业务工作总结
2015/04/27 职场文书
幼儿园2016年圣诞活动总结
2016/03/31 职场文书
python 如何执行控制台命令与操作剪切板
2021/05/20 Python
MySQL脏读,幻读和不可重复读
2022/05/11 MySQL