机器学习-周志华-个人练习9.4

来源:互联网 发布:怒战辅助软件 编辑:程序博客网 时间:2024/04/30 00:05

9.4 试编程实现k均值算法,设置3组不同的k值,3组不同初始中心点,在西瓜数据集4.0上进行实验比较,并讨论什么样的初始中心有利于取得好结果。

根据k均值算法的迭代公式,可以知道在二维平面上,这些中心点直接由其几何位置的两点间垂直平分线作为聚类边界,因此在数据不多的情况下,很容易陷入局部最优,从而使迭代过程很快结束。实际执行代码发现,所谓取得好结果,应该是使各点离聚类边界尽量远,且最终的中心点相互远离。个人推测,由于在更新中心向量的时候使用了平均,因而所有中心会尽量向点分布密度较大的区域移动,因此,初始中心应该尽量分散到不同的高点密度分布区域上去,可取得较好结果。

本题的算法十分简单,不过如果直接采用与书上相同的初始中心,则马上就会收敛而不会像书上所说训练5轮才达到收敛。也就是说,书上给的示例是错的。

另外,通过这个题,我才发现,原来用matplotlib可以画动图,利用animation里面的ArtistAnimation或者FuncAnimation即可。然而,我发现不能理想地导出gif图,这就比较尴尬了。。。网上搜了一下发现,需要装ImageMagick这个软件,然而装了还是各种错,后来找到matplotlib的配置文件,在最后一行更改convert_path为convert.exe的安装路径也仍然不行,还报错:winError 5,后来找到一篇帖子一篇帖子,讲到了这个问题,就是直接找到matplotlib的__init__.py,

# this is the instance used by the matplotlib classesrcParams = rc_params()
找到上面这一行,在后面加上一行:

rcParams['animation.convert_path'] = 'D:\...\convert.exe'  # 你的convert.exe的安装路径
这样就可以完美运行啦,生成的gif占用空闲小而且非常清晰,比用录屏软件截出来的好很多。好了,废话不多说了,上代码和图。

# -*- coding: utf-8 -*-import numpy as npimport matplotlib.pyplot as pltimport matplotlib.animation as animationdef kmeans(data, center_ids, max_err=0.0001, max_round=30):    init_centers = []    n = len(center_ids)    for id in center_ids:        init_centers.append(data[id,:])    error, rounds = 1.0, 0    while error > max_err and rounds < max_round:        rounds += 1        clusters = []        for _ in range(n):            clusters.append([])        for j in range(len(data)):            dist = []            for i in range(n):                vector = data[j,:] - init_centers[i]                d_ji = np.dot(vector, vector) ** 0.5                dist.append(d_ji)            near_id = sorted(enumerate(dist), key=lambda x: x[1])[0][0]            clusters[near_id].append(j)        new_center = [0]* n        error = 0        for i in range(n):            new_center[i] = np.sum(data[clusters[i],:], axis=0)            new_center[i] /= len(clusters[i])            vec = new_center[i] - init_centers[i]            err = np.dot(vec,vec) ** 0.5            if err:                init_centers[i] = new_center[i]                error += err        yield clusters, new_center,rounds  # 用yield可以得到每一轮训练后的聚类情况,最终返回的是一个生成器data = np.array([    [0.697, 0.460],[0.774, 0.376],[0.634, 0.264],[0.608, 0.318],[0.556, 0.215],    [0.403, 0.237],[0.481, 0.149],[0.437, 0.211],[0.666, 0.091],[0.243, 0.267],    [0.245, 0.057],[0.343, 0.099],[0.639, 0.161],[0.657, 0.198],[0.360, 0.370],    [0.593, 0.042],[0.719, 0.103],[0.359, 0.188],[0.339, 0.241],[0.282, 0.257],    [0.748, 0.232],[0.714, 0.346],[0.483, 0.312],[0.478, 0.437],[0.525, 0.369],    [0.751, 0.489],[0.532, 0.472],[0.473, 0.376],[0.725, 0.445],[0.446, 0.459]])init_centers = [12,22]  # 对应的是选择的初始中心样本的id,这也同时代表了选择的聚类数目fig,ax = plt.subplots(1,1,figsize=(5,5))ax.set_xlim(0, 1)ax.set_ylim(0, 0.6)ax.set_ylabel('sugar')ax.set_xlabel('density')imgs = []for cluster, center, rounds in kmeans(data, init_centers):  # 对各轮聚类的结果进行保存,存入imgs    pics,dye = [], ['red', 'orange', 'green', 'blue', 'pink']    ax.set_title('clusters in %s rounds' % rounds)    for i, li in enumerate(cluster):        pics.append(ax.scatter(data[li, 0], data[li, 1], c=dye[i]))        pics.append(ax.scatter(center[i][0], center[i][1], s=45,c='gray', marker='s',))    imgs.append(pics)imgs.insert(0, [ax.scatter(data[:,0],data[:,1], c='k')])A = animation.ArtistAnimation(fig, imgs, interval=1000, blit=True, repeat_delay=500)plt.show()A.save('3point.gif',fps=2, writer='imagemagick')  # 设置保存路径,gif图每秒帧数
2类聚类:


3类聚类:


4类聚类:


0 0
原创粉丝点击