您的位置:首页 > 编程语言 > Python开发

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

2017-05-07 18:10 387 查看

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 classes
rcParams = rc_params()
找到上面这一行,在后面加上一行:

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

# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

def 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类聚类:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息