继续来看第三章, 下面是用图形显示树
首先下载 PIL, 这个库目前不支持 python 3, 下面地址上有高手改过的版本可以用:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil
显示画图不是本书重点, 就不解释了, 就是教你怎么用PIL画图
列聚类
刚才的聚类我们发现了博客之间的相关度, 有什么样博客是类似的, 如果我们对转置后数据进行聚类呢?就是对列, 也是博客出现的单词进行聚类, 这样显示的结果就是单词的关联度, 同时反映博客的类型。
显示要把原来的数据转置, 这个很简单
def rotamatrix(data):
rotadata = []
for i in range(len(data[0])):
newrow = [data[j][i] for j in range(len(data))]
rotadata.append(newrow)
return rotadata
结果为:
需要注意的是这个时候 数据项是单词, 变量是博客, 单词多很多, 在聚类是无意义的结果也很多, 博客聚类更有意义
K 均值聚类
分级聚类我们看到, 算法复杂度太高, 计算太耗时,数据集大会很慢, 就像刚才我们进行单词聚类, 时间就很长,还有一个问题 树形结构不会真正将数据拆分成不同组(需要额外保存下这种关系)
K均值聚类的做法, 先预设K个目标点, 然后将数据集分类, 分配到这k个点上, 分配原则是离谁近就放到谁附近, 分完一次后, 调整一下, 计算k个聚类在一起的群的中心点, 利用新得出的中心点再次聚类,直到某一次, 聚类过程中结果不发生变化就停止,算法实现如下
def kcluster(rows, distance=pearson, k=4):
ranges = [(min([row[i] for row in rows]), max([row[i] for row in rows]))
for i in range(len(rows[0]))]
clusters = [ [random.random * (ranges[i][1] - ranges[i][0]) + ranges[i][0]for i in range(len(rows[0]))]for j in range(k)]
lastMatches = None
for t in range(100):
print('Iteration %d' % t)
bestmatches = [[] for i in range(k)]
for j in range(len(rows)):
row = rows[j]
bestmatch = 0
for i in range(k):
d = distance(clusters[i], row)
if d < distance(clusters[bestmatch], row): bestmatch = i
bestmatches[bestmatch].append(j)
if bestmatches == lastMatches: break
lastMatches = bestmatches
for i in range(k):
avgs = [0.0] * len(rows[0])
length = len(bestmatches[i])
if length > 0:
for rowid in bestmatches[i]:
for m in range (len(rows[rowid])):
avgs[m] += rows[rowid][m]
for j in range(len(avgs)):
avgs[j] /= length
clusters[i] = avgs
return bestmatches