有了上篇得到的两个计算集群的模块,我们可以很轻松计算指定个数的集群了。那么结果如何呈现呢?
老师给了一张美国地图,大小(像素)跟数据中的坐标相符,于是我们就可以把结果呈现到图上。嗯,也就是用matplotlib把点画到已经存在的图上。
首先是载入图片:
map_file = open(MAP_URL)
map_img = plt.imread(map_file)
implot = plt.imshow(map_img)
只要调用一下plt.show()就可以显示图片了。但是提前预览一下就知道图片很小,我们要提高一下分辨率,为了照顾好图片的长宽,我们可以找个把图片等比缩小一下,然后直接设置成figure的DPI。
ypixels, xpixels, bands = map_img.shape
DPI = 60.0 # adjust this constant to resize your plot
xinch = xpixels / DPI
yinch = ypixels / DPI
plt.figure(figsize=(xinch,yinch))
这样图看着就会舒服点,如果嫌图太小,调低DPI即可。
后面的又是老师给出的小技巧。怎么表示集群归属呢?
首先要理解给定的数据。给定的数据每一行有五个数据,第一个是fips_code,是county(县?)的邮政编码(?);第二第三就是坐标,第四个就是人口,第五个是患病风险。
本来可以直接把集群直接按照人口的大小标准化之后作为圆的面积,绘到美国地图上,但是那样的话地图上就剩下了一个又一个的大圆,不直观,也毁了原来的数据。
老师建议把给定的数据原原本本的绘出来,然后使用相同的颜色表示同一集群,是不是更好?不能更认同了。
首先就是调整个合适的比例,使用圆的面积表示county的人口:
def circle_area(pop):
return math.pi * pop / (200.0 ** 2)
当初我们融合集群的时候,把fips_code合并成了一个集合,也就是说,我们要把融合之后的集群中的fips_code取出来,然后绘成同一种颜色。于是建立一个字典,根据fips_code,查找county在原来数据(data_table)中的位置:
fips_to_line = {}
for line_idx in range(len(data_table)):
fips_to_line[data_table[line_idx][0]] = line_idx
然后我们就可以把数据绘在地图上了:
for cluster_idx in range(len(cluster_list)):
cluster = cluster_list[cluster_idx]
cluster_color = COLORS[cluster_idx % len(COLORS)]
for fips_code in cluster.fips_codes():
line = data_table[fips_to_line[fips_code]]
plt.scatter(x = [line[1]], y = [line[2]], s = circle_area(line[3]), lw = 1,
facecolors = cluster_color, edgecolors = cluster_color)
其中,data_table是计算集群前的数据,cluster_list是计算集群后的数据。COLORS是一个颜色的list,基本可以避免不同集群的颜色重叠。
结果也蛮炫的,hierarchical的结果为:(就是分离合并算法)
而k-means算法的结果为:(先随便取点,然后迭代)
注意观察左下角(洛杉矶?)和右下角的部分,二者所出现的不同。
hierarchical算法的结果基本符合预期,那k-means算法的误差是如何得来的呢?
k-means算法的初始值是取的人口最大的几个county,如果恰好有两个大county在一起,误差就会出现,而且经过几次的迭代,误差也不会消除。因此k-means需要人工干预,通过取理想的初始值,来达到预期。
k-means算法的优势也很明显,k-means通常只需要几分钟,要是把github上的源代码下载下来运行一下就会知道,运行hierarchical算法的时间是足够take a shower的。
——————————————————
如果仅仅让我自己去解决这个问题,恐怕我会把事情搞的无比复杂,而且最终的结果也并不一定如意。通过老师的引导,发现事情一下子就清晰明了。要解决一个问题,一定要多去思考,看看是否有合适的路到达。
比如这个问题中的每组数据包含五个变量,不如就以此建个类。考虑到要做的运算,也提前内建好method。这样就极大的简化了整个过程。
另外,数据的呈现也不要太粗暴,比如我一开始想到的直接绘圆,实在不是什么好点子。
Long long way to go !
源代码:Github