凝聚层次聚类:
MIN,该方法在合并时,只要依次取当前最*的点对,如果这个点对当前不在一个簇中,将所在的两个簇合并就行:
(MIN):定义簇的邻*度为不同两个簇的两个最*的点之间的距离。
(MAX):定义簇的邻*度为不同两个簇的两个最远的点之间的距离。
(3)组*均:定义簇的邻*度为取自两个不同簇的所有点对邻*度的*均值。
根据该算法,实现如下代码。开始时计算每个点对的距离,并按距离降序依次合并。另外为了防止过度合并,定义的退出条件是90%的簇被合并,即当前簇数是初始簇数的10%:
实现代码如下:
1. # scoding=utf-8
2. # Agglomerative Hierarchical Clustering(AHC)
3. import pylab as pl
4. from operator import itemgetter
5. from collections import OrderedDict,Counter
6.
7. points = [[int(eachpoint.split('#')[0]), int(eachpoint.split('#')[1])] for eachpoint in open("points","r")]
8.
9. # 初始时每个点指派为单独一簇
10. groups = [idx for idx in range(len(points))]
11.
12. # 计算每个点对之间的距离
13. disP2P = {}
14. for idx1,point1 in enumerate(points):
15. for idx2,point2 in enumerate(points):
16. if (idx1 < idx2):
17. 0]-point2[0]),2) + pow(abs(point1[1]-point2[1]),2)
18. "#"+str(idx2)] = distance
19.
20. # 按距离降序将各个点对排序
21. disP2P = OrderedDict(sorted(disP2P.iteritems(), key=itemgetter(1), reverse=True))
22.
23. # 当前有的簇个数
24. groupNum = len(groups)
25.
26. # 过分合并会带入噪音点的影响,当簇数减为finalGroupNum时,停止合并
27. finalGroupNum = int(groupNum*0.1)
28.
29. while groupNum > finalGroupNum:
30. # 选取下一个距离最*的点对
31. twopoins,distance = disP2P.popitem()
32. '#')[0])
33. '#')[1])
34.
35. pointAGroup = groups[pointA]
36. pointBGroup = groups[pointB]
37.
38. # 当前距离最*两点若不在同一簇中,将点B所在的簇中的所有点合并到点A所在的簇中,此时当前簇数减1
39. if(pointAGroup != pointBGroup):
40. for idx in range(len(groups)):
41. if groups[idx] == pointBGroup:
42. groups[idx] = pointAGroup
43. 1
44.
45. # 选取规模最大的3个簇,其他簇归为噪音点
46. wantGroupNum = 3
47. finalGroup = Counter(groups).most_common(wantGroupNum)
48. finalGroup = [onecount[0] for onecount in finalGroup]
49.
50. dropPoints = [points[idx] for idx in range(len(points)) if groups[idx] not in finalGroup]
51.
52. # 打印规模最大的3个簇中的点
53. group1 = [points[idx] for idx in xrange(len(points)) if groups[idx]==finalGroup[0]]
54. group2 = [points[idx] for idx in xrange(len(points)) if groups[idx]==finalGroup[1]]
55. group3 = [points[idx] for idx in xrange(len(points)) if groups[idx]==finalGroup[2]]
56. pl.plot([eachpoint[0] for eachpoint in group1], [eachpoint[1] for eachpoint in group1], 'or')
57. pl.plot([eachpoint[0] for eachpoint in group2], [eachpoint[1] for eachpoint in group2], 'oy')
58. pl.plot([eachpoint[0] for eachpoint in group3], [eachpoint[1] for eachpoint in group3], 'og')
59.
60. # 打印噪音点,黑色
61. pl.plot([eachpoint[0] for eachpoint in dropPoints], [eachpoint[1] for eachpoint in dropPoints], 'ok')
62.
63. pl.show()
另外我们可以看出凝聚的层次聚类并没有类似基本K均值的全局目标函数,没有局部极小问题或是很难选择初始点的问题。合并的操作往往是最终的,一旦合并两个簇之后就不会撤销。当然其计算存储的代价是昂贵的。