python实现kMeans算法


Posted in Python onDecember 21, 2017

聚类是一种无监督的学习,将相似的对象放到同一簇中,有点像是全自动分类,簇内的对象越相似,簇间的对象差别越大,则聚类效果越好。

1、k均值聚类算法

k均值聚类将数据分为k个簇,每个簇通过其质心,即簇中所有点的中心来描述。首先随机确定k个初始点作为质心,然后将数据集分配到距离最近的簇中。然后将每个簇的质心更新为所有数据集的平均值。然后再进行第二次划分数据集,直到聚类结果不再变化为止。

伪代码为

随机创建k个簇质心
当任意一个点的簇分配发生改变时:
    对数据集中的每个数据点:
        对每个质心:
            计算数据集到质心的距离
        将数据集分配到最近距离质心对应的簇
    对每一个簇,计算簇中所有点的均值并将均值作为质心

python实现

import numpy as np
import matplotlib.pyplot as plt

def loadDataSet(fileName): 
 dataMat = [] 
 with open(fileName) as f:
  for line in f.readlines():
   line = line.strip().split('\t')
   dataMat.append(line)
 dataMat = np.array(dataMat).astype(np.float32)
 return dataMat


def distEclud(vecA,vecB):
 return np.sqrt(np.sum(np.power((vecA-vecB),2)))
def randCent(dataSet,k):
 m = np.shape(dataSet)[1]
 center = np.mat(np.ones((k,m)))
 for i in range(m):
  centmin = min(dataSet[:,i])
  centmax = max(dataSet[:,i])
  center[:,i] = centmin + (centmax - centmin) * np.random.rand(k,1)
 return center
def kMeans(dataSet,k,distMeans = distEclud,createCent = randCent):
 m = np.shape(dataSet)[0]
 clusterAssment = np.mat(np.zeros((m,2)))
 centroids = createCent(dataSet,k)
 clusterChanged = True
 while clusterChanged:
  clusterChanged = False
  for i in range(m):
   minDist = np.inf
   minIndex = -1
   for j in range(k):
    distJI = distMeans(dataSet[i,:],centroids[j,:])
    if distJI < minDist:
     minDist = distJI
     minIndex = j
   if clusterAssment[i,0] != minIndex:
    clusterChanged = True
   clusterAssment[i,:] = minIndex,minDist**2
  for cent in range(k):
   ptsInClust = dataSet[np.nonzero(clusterAssment[:,0].A == cent)[0]]
   centroids[cent,:] = np.mean(ptsInClust,axis = 0)
 return centroids,clusterAssment



data = loadDataSet('testSet.txt')
muCentroids, clusterAssing = kMeans(data,4)
fig = plt.figure(0)
ax = fig.add_subplot(111)
ax.scatter(data[:,0],data[:,1],c = clusterAssing[:,0].A)
plt.show()

print(clusterAssing)

2、二分k均值算法

K均值算法可能会收敛到局部最小值,而非全局最小。一种用于度量聚类效果的指标为误差平方和(SSE)。因为取了平方,更加重视原理中心的点。为了克服k均值算法可能会收敛到局部最小值的问题,有人提出来二分k均值算法。
首先将所有点作为一个簇,然后将该簇一分为二,然后选择所有簇中对其划分能够最大程度减低SSE的值的簇,直到满足指定簇数为止。

伪代码

将所有点看成一个簇
计算SSE
while 当簇数目小于k时:
    for 每一个簇:
        计算总误差
        在给定的簇上进行k均值聚类(k=2)
        计算将该簇一分为二的总误差
    选择使得误差最小的那个簇进行划分操作

python实现

import numpy as np
import matplotlib.pyplot as plt

def loadDataSet(fileName): 
 dataMat = [] 
 with open(fileName) as f:
  for line in f.readlines():
   line = line.strip().split('\t')
   dataMat.append(line)
 dataMat = np.array(dataMat).astype(np.float32)
 return dataMat


def distEclud(vecA,vecB):
 return np.sqrt(np.sum(np.power((vecA-vecB),2)))
def randCent(dataSet,k):
 m = np.shape(dataSet)[1]
 center = np.mat(np.ones((k,m)))
 for i in range(m):
  centmin = min(dataSet[:,i])
  centmax = max(dataSet[:,i])
  center[:,i] = centmin + (centmax - centmin) * np.random.rand(k,1)
 return center
def kMeans(dataSet,k,distMeans = distEclud,createCent = randCent):
 m = np.shape(dataSet)[0]
 clusterAssment = np.mat(np.zeros((m,2)))
 centroids = createCent(dataSet,k)
 clusterChanged = True
 while clusterChanged:
  clusterChanged = False
  for i in range(m):
   minDist = np.inf
   minIndex = -1
   for j in range(k):
    distJI = distMeans(dataSet[i,:],centroids[j,:])
    if distJI < minDist:
     minDist = distJI
     minIndex = j
   if clusterAssment[i,0] != minIndex:
    clusterChanged = True
   clusterAssment[i,:] = minIndex,minDist**2
  for cent in range(k):
   ptsInClust = dataSet[np.nonzero(clusterAssment[:,0].A == cent)[0]]
   centroids[cent,:] = np.mean(ptsInClust,axis = 0)
 return centroids,clusterAssment

def biKmeans(dataSet,k,distMeans = distEclud):
 m = np.shape(dataSet)[0]
 clusterAssment = np.mat(np.zeros((m,2)))
 centroid0 = np.mean(dataSet,axis=0).tolist()
 centList = [centroid0]
 for j in range(m):
  clusterAssment[j,1] = distMeans(dataSet[j,:],np.mat(centroid0))**2
 while (len(centList)<k):
  lowestSSE = np.inf
  for i in range(len(centList)):
   ptsInCurrCluster = dataSet[np.nonzero(clusterAssment[:,0].A == i)[0],:]
   centroidMat,splitClustAss = kMeans(ptsInCurrCluster,2,distMeans)
   sseSplit = np.sum(splitClustAss[:,1])
   sseNotSplit = np.sum(clusterAssment[np.nonzero(clusterAssment[:,0].A != i)[0],1])
   if (sseSplit + sseNotSplit) < lowestSSE:
    bestCentToSplit = i
    bestNewCents = centroidMat.copy()
    bestClustAss = splitClustAss.copy()
    lowestSSE = sseSplit + sseNotSplit
  print('the best cent to split is ',bestCentToSplit)
#  print('the len of the bestClust')
  bestClustAss[np.nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList)
  bestClustAss[np.nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit

  clusterAssment[np.nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:] = bestClustAss.copy()
  centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]
  centList.append(bestNewCents[1,:].tolist()[0])
 return np.mat(centList),clusterAssment

data = loadDataSet('testSet2.txt')
muCentroids, clusterAssing = biKmeans(data,3)
fig = plt.figure(0)
ax = fig.add_subplot(111)
ax.scatter(data[:,0],data[:,1],c = clusterAssing[:,0].A,cmap=plt.cm.Paired)
ax.scatter(muCentroids[:,0],muCentroids[:,1])
plt.show()

print(clusterAssing)
print(muCentroids)

代码及数据集下载:K-means

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

Python 相关文章推荐
python2.7删除文件夹和删除文件代码实例
Dec 18 Python
Python socket C/S结构的聊天室应用实现
Nov 30 Python
使用Python编写一个模仿CPU工作的程序
Apr 16 Python
Bottle框架中的装饰器类和描述符应用详解
Oct 28 Python
Python切片工具pillow用法示例
Mar 30 Python
python修改list中所有元素类型的三种方法
Apr 09 Python
浅谈Tensorflow由于版本问题出现的几种错误及解决方法
Jun 13 Python
python实现字符串和字典的转换
Sep 29 Python
Win10系统下安装labelme及json文件批量转化方法
Jul 30 Python
python如何建立全零数组
Jul 19 Python
python利用线程实现多任务
Sep 18 Python
Django框架模板用法详解
Jun 10 Python
利用Tkinter(python3.6)实现一个简单计算器
Dec 21 #Python
python编写朴素贝叶斯用于文本分类
Dec 21 #Python
python并发2之使用asyncio处理并发
Dec 21 #Python
利用Python暴力破解zip文件口令的方法详解
Dec 21 #Python
Python人脸识别初探
Dec 21 #Python
python中判断文件编码的chardet(实例讲解)
Dec 21 #Python
python 设置文件编码格式的实现方法
Dec 21 #Python
You might like
乱谈我对耳机、音箱的感受
2021/03/02 无线电
调用WordPress函数统计文章访问量及PHP原生计数器的实现
2016/03/21 PHP
PHP页面跳转操作实例分析(header方法)
2016/09/28 PHP
Zend Framework实现自定义过滤器的方法
2016/12/09 PHP
Javascript入门学习资料收集整理篇
2008/07/06 Javascript
javascript 获取元素位置的快速方法 getBoundingClientRect()
2009/11/26 Javascript
jQuery使用$.ajax进行异步刷新的方法(附demo下载)
2015/12/04 Javascript
JS创建对象几种不同方法详解
2016/03/01 Javascript
JQuery的attr 与 val区别
2016/06/12 Javascript
jQuery 翻页组件yunm.pager.js实现div局部刷新的思路
2016/08/11 Javascript
JS实现快速的导航下拉菜单动画效果附源码下载
2016/11/01 Javascript
微信小程序 textarea 详解及简单使用方法
2016/12/05 Javascript
JS无缝滚动效果实现方法分析
2016/12/21 Javascript
AngularJs篇:使用AngularJs打造一个简易权限系统的实现代码
2016/12/26 Javascript
ES6字符串模板,剩余参数,默认参数功能与用法示例
2017/04/06 Javascript
基于Node的React图片上传组件实现实例代码
2017/05/10 Javascript
JS点击图片弹出文件选择框并覆盖原图功能的实现代码
2017/08/25 Javascript
vue 监听键盘回车事件详解 @keyup.enter || @keyup.enter.native
2018/08/25 Javascript
Element Input组件分析小结
2018/10/11 Javascript
[02:48]DOTA2英雄基础教程 暗夜魔王
2013/12/12 DOTA
详解python进行mp3格式判断
2016/12/23 Python
Python3实现二叉树的最大深度
2019/09/30 Python
10款最佳Python开发工具推荐,每一款都是神器
2020/10/15 Python
abstract是什么意思
2012/02/12 面试题
工程造价专业大专生求职信
2013/10/06 职场文书
应届生法律求职信
2013/10/22 职场文书
美术毕业生求职信
2014/02/25 职场文书
聚美优品励志广告词
2014/03/14 职场文书
难以忽视的真相观后感
2015/06/05 职场文书
小学生纪律委员竞选稿
2015/11/19 职场文书
2016年感恩教师节活动总结
2016/04/01 职场文书
高中优秀作文(范文)
2019/08/15 职场文书
Python基础之元类详解
2021/04/29 Python
解决golang结构体tag编译错误的问题
2021/05/02 Golang
基于Redis实现分布式锁的方法(lua脚本版)
2021/05/12 Redis
深入浅析Redis 集群伸缩原理
2021/05/15 Redis