博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于numpy实现的简单k-means,k-means浅析
阅读量:3967 次
发布时间:2019-05-24

本文共 2993 字,大约阅读时间需要 9 分钟。

基于numpy实现的简单k-means

该文从简单的数据角度讲解基于k-means和基于numpy实现k-means代码。


文章目录


前言

k-means是什么,它的做什么的,它与先前所说的聚类有什么关系。


一、 k-means

上一篇文章已经详解了聚类,那么基础应该已经没有什么问题了,k-means其实就是用中文来说的话就是k均值聚类,它属于聚类中的"基于原型的聚类"

基于原型的聚类:假设聚类结构能通过一组原型刻画,通常情况下,算法先对原型进行初始化,继而对原型进行不断的更新迭代。而不同的更新方式和不同的求解将产生不同的算法。

k均值算法

官方定义:给定样本集D={x1,x2,…,xn};所谓k均值算法,是求得针对聚类所得簇划分C={C1,C2…,Ck}最小化的平方误差,如下

在这里插入图片描述

其中:
在这里插入图片描述

那么μi就可以看为是x集合也就是Ci的均值向量。直观的来看,E在一定程度上刻画了簇内的所有样本围绕簇均值向量的紧密程度。E越小则,越紧密,意味着簇内相似度越高。我们只需要求最小E即可。

接下来我们解析官方这些概念和公式:

从概念入手,我们知道最后是要把数据集划分为K个簇,那么"均值"这个俩个字,也很容易理解,从公式入手,所谓的均值其实指的就是均值向量了。那么如果要实现该算法的话,我们只需要几步:

  1. 随机选取k个质心,因为要求有k个簇。
  2. 接下来求解每个样本到所有质心的距离,并得到最小距离,将该样本归入该质心属于的簇之中
  3. 计算簇均值向量
  4. 判断簇均值向量是否与上次确定的簇均值向量相等,若相等,则返回簇若不相等,则继续迭代,同时设置迭代上限,防止没有结果的崩溃。

从理论上来说,该方法,适用于所有的数据集,无论是有序属性还是无序属性,需要变更的仅仅是距离的算法问题罢了。

  • 显然不难理解,这是k-means的优点之一,同时它还拥有了收敛速度快,聚类效果优,调参简单等优点。

二、代码原理实现

1.引入库

代码如下(示例):

#基于numpy的K-means#coding:UTF-8#倒库import numpy as npimport random as rdimport matplotlib.pyplot as pltfrom math import *

2.面向对象实现

class k_m():    #计算距离 返回欧氏距离 这里仅仅考虑到了有序属性    def __init__(self):        self.color=['.b','.g','.r','.c','.m','.y','.k','.w']        self.cencolor=['*b','*g','*r','*c','*m','*y','*k','*w']        #0表示当前颜色的索引        self.now=0    def dist(x,y):        return sqrt(pow(x[0]-y[0],2)+pow(x[1]-y[1],2))    #crowd_count:簇的个数,也是定义K_means点的个数,传入x坐标和y坐标,    def k_means(self,x,y,k):        #获取含有k个随机属性的属性序列         k_list=[(x[i],y[i]) for i in rd.sample(range(len(x)),k)]         #对属性排序,以便处理        k_list.sort()        while 1:        #crowds为簇列表,每一次遍历都要更新簇列表            crowds=[[] for i in range(k)]            for i in range(len(x)):                t_now=(x[i],y[i])                 #计算到所有点的距离 存列表 接下来我们需要该点到所有质心的距离最近并且将其加入簇列表中                all_dist=[k_m.dist(k_list[j],t_now) for j in range(k)]                min_dist=all_dist.index(min(all_dist))                #加入索引之中                crowds[min_dist].append(i)            #进入质心的迭代                centroid_news_list=[]            #从之前得到的簇中计算均值,重新确定质心并进行运算            for i in range(k):                x_t=sum(x[j] for j in crowds[i])/len(crowds[i])                y_t=sum(y[j] for j in crowds[i])/len(crowds[i])                centroid_news_list.append((x_t,y_t))            centroid_news_list.sort()            #绘图            plt.figure()            plt.title('k={0:d} k-means'.format(k))            for i in range(k):                #绘点                plt.plot([x[j] for j in crowds[i]],[y[j] for j in crowds[i]],self.color[self.now])#                #绘质心                plt.plot(k_list[i][0],k_list[i][1],self.cencolor[self.now])#                self.now+=1            plt.show()            plt.close('all')            if centroid_news_list==k_list:                return crowds            else:                self.now=0                k_list=centroid_news_list
  • 看完代码之后不难发现,该代码非常简单,但同样,其处理能力也有限,因为该代码只是为了从原理角度浅析k-means算法,因此不会用于处理很复杂的数据,但是是其对二元组数据处理仍然十分优秀,这边博主已经用数据集测试过了,代码没有bug可以放心参考。

总结

k-means本身作为原型聚类中最著名的划分聚类算法,以及最为广泛使用的划分聚类算法,其优秀程度自然是不言而喻。有兴趣的小伙伴可以尝试用无序属性的数据集,以及无序距离的计算处理复杂任务,比如物品的分类等等,实现也没有很难,但是十分有用。

转载地址:http://ukcki.baihongyu.com/

你可能感兴趣的文章
POSIX定时器timer_create()以及线程中的gettid() 和pthread_self()
查看>>
c /c++中日期和时间的获取:strftime()函数
查看>>
C语言 回调函数
查看>>
c语言swap(a,b)值交换的4种实现方法
查看>>
C++小知识点
查看>>
【转载】zedboard中PL_GPIO控制(8个sw、8个leds)
查看>>
zedboard烧写程序到FLASH,用于QSPI Flash启动
查看>>
软件工程师,你必须知道的20个常识
查看>>
常用STL算法2_查找
查看>>
常用STL算法3_排序
查看>>
常用STL算法4_拷贝和替换
查看>>
STL综合案例
查看>>
O(logn)时间复杂度求Fibonacci数列
查看>>
【转】腾讯十年运维老兵:运维团队的五个“杀手锏”
查看>>
Iterator_traits
查看>>
Zedboard中的SPI通信记录文档(已实现)
查看>>
Android 发布到google Play的app搜索不到问题的解决
查看>>
Flutter 网络请求之基于dio的简单封装
查看>>
Flutter UI基础 - 路由之Navigator详解
查看>>
Flutter UI基础 - Widgets 之 InkWell 和 Ink
查看>>