本文主要讨论使用matplotlib保存gif动画,K-Means聚类是一个很基础的聚类方法,基本过程如下:
- 给定一组样本,确定k值,即类别数目
- 随机初始化k个聚类的中心(下称中心)
- 计算每个样本与每一个中心的相似的程度——距离
- 考察每个样本,离哪一个中心更近,就将该样本分为哪一类
- 所有样本划分完毕后,重新计算聚类的中心
- 重复3、4、5,直到中心不变或者变化很小
上述过程的3、4、5步需要展开一下。首先是第3步,使用欧式距离:
其中,
一个样本有
然后是第4步,这里举一个具体的栗子。例如有80个样本,每个样本含有2个特征值。现在令
将所有样本作为一个二维数组,其shape为
将4个中心作为一个二维数组,其shape为
完成第3步的计算以后得到一个结果,其shape应为
关于这两步,numpy没有现成的函数可以一步到位,所以使用自定义的ufunc函数
class
在calc_distance中计算距离时没有开方,是因为不开方不会影响单调性,所以省了
最后是第5步,根据现有的中心将所有的样本分类
K-means简单讨论到这里,然后时使用matplotlib保存聚类过程为一个gif动画,首先把直接效果贴出来
为了增加视觉效果,动态调整了每个聚类的点的大小。现在进入正题,要保存gif动画需要用到matplotlib的一个类:
from
该类的初始化如下
def
上面的代码列举了FuncAnimation类初始化的几个关键参数,注释已经写的比较详细,只针对func和init_func展开讨论
init_func 是动画的初始化函数,也可以不设置,该函数的过程无非就是前面讨论的,将样本分类,根据分类的样本计算新的中心。然后用分好类的样本数据进行散点图的绘制,并且将散点图的对象放在一个元组中返回(必须是元组)
def setup(self, colors=['r', 'g', 'b', 'k']):
'''
动画初始化函数
'''
cs = self.get_classified_sample() # 得到分类后的样本
tmp = []
for i in np.arange(self.k): # 绘制已分类的样本
tmp.append(self.ax.scatter(cs[i][:,0], cs[i][:,1], c=colors[i], animated=True))
for i in np.arange(self.k): # 绘制中心
tmp.append(self.ax.scatter(self.center[i,0], self.center[i,1], c=colors[i], s=150, marker='x', animated=True))
self.sc = tuple(tmp) # 必须转换为元组
for i in np.arange(self.k): # 更新每个簇的中心
self.center[i,:] = cs[i].mean(axis=0)
return self.sc # 返回必须是元组
上面的代码中有的函数还没贴出来显得有点凌乱,我会在文章最后给出github的链接,包括完整代码,测试数据,以及生成的动画
另外func参数要传入一个函数,该函数会在绘制每一帧动画时调用,同样也是返回一个包含散点图对象的元组
def
通过上面的两个参数的解释,想必应该清楚这个动画是怎么生成的了,其实就是在这两个函数中生成matplotlib的绘图对象,或者调整其属性,然后FuncAnimation对象就会根据你返回的对象绘制每一帧的图像,最后组成动画
最后是实现的链接:
完整实现github.com