DIANA算法

  1. DIANA(Divisive Analysis)算法屬於分裂的層次聚類,首先將所有的對象初始化到一個簇中,然後根據一些原則(比如最鄰近的最大歐式距離),將該簇分類。 直到到達用戶指定的簇數目或者兩個簇之間的距離超過了某個閾值。

    • 簇的直徑:在一個簇中的任意兩個數據點都有一個歐氏距離,這些距離中的最大值是簇的直徑
    • 平均相異度(平均距離)
  2. 算法描述:

    - 輸入:包含n個對象的數據庫,終止條件簇的數目k
    - 輸出:k個簇,達到終止條件規定簇數目
    		1. 將所有對象整個當成一個初始簇[將每個點當成一個初始簇]
    		2. For (i=1;i!=k;i++) Do Begin
    		3.      在所有簇中挑選出具有最大直徑的簇C
    		4.      找出C與其他點**平均相異度最大**的一個點P放入splinter group,
    		5.      剩餘的放入old party中。
    		5.    Repeat
    		6.      在old party裏找出**到splinter group中點的最近距離** <= **到old party中點的最近距離的點**,並將該點加入splinter group
    		7.    Until 沒有新的old party的點被分配給splinter group;
    		8. Splinter group 和old party爲被選中的簇分裂成的兩個簇,與其他簇一起組成新的簇集合
    		9. END	
    - 算法性能: 缺點是已做的分裂操作不能撤銷,類之間不能交換對象。如果在某步沒有選擇好分裂點,可能會導致低質量的聚類結果。大數據集不太適用。
    
  3. 具體理解:

    1. 數據:
      • 序號 屬性1 屬性2
      • 1 1 1
      • 2 1 2
      • 3 2 1
      • 4 2 2
      • 5 3 4
      • 6 3 5
      • 7 4 4
      • 8 4 5
    2. 實例分析:
      1. 對於所給的數據進行DIANA算法,(設n=8,用戶輸入的終止條件爲兩個簇), 初始簇{1,2,3,4,5,6,7,8}。
      2. 第一步,找到具有最大直徑的簇,對簇中的每個點計算平均相異度
        1. 序號1的平均距離(就是1距離其他各個點的距離長度之和除以7)
          • s1=(1+1+1.1414+3.6+4.24+4.47+5)/7=2.96;
          • [這裏取兩位小數, 代碼運行實際更精確.]
        2. 序列2的平均距離 s2=(1+1.414+1+2.828+3.6+3.6+4.24)/7=2.526;
        3. 序列3的平均距離 s3=(1+1.414+1+3.16+4.12+3.6+4.27)/7=2.68;
        4. 序列4的平均距離 s4=(1.414+1+1+2.24+3.16+2.828+3.6)/7=2.18
        5. 序列5的平均距離 s5=2.18;
        6. 序列6的平均距離 s6=2.68;
        7. 序列7的平均距離 s7=2.526;
        8. 序列8的平均距離 s8=2.96;
        9. 將8個點的平均距離中:
          • 挑選一個最大平均相異度的 點1 放入splinter group中
          • 剩餘點放在old party中
          • splinter group={1}
          • old party={2,3,4,5,6,7,8}
      3. 第二步,在old party裏找出到splinter group的距離小於到old party的距離的點,將該點放入splinter group中,該點就是2;
        • splinter group={1,2}, old party={3,4,5,6,7,8}
      4. 第三步,在old party裏找出到splinter group的距離小於到old party的距離的點,將該點放在splinter group中,該點就是3;
        • spliner group={1,2,3}, old party={4,5,6,7,8}
      5. 第四步,在old party裏找出到splinter group的距離小於到old party的距離的點,將該點放在splinter group中,該點就是4;
        • spliner group={1,2,3,4}, old party={5,6,7,8}
      6. 第五步, 在old party裏找出到splinter group的距離小於到old party的距離的點
        • 此時的分裂的簇數爲2,已經達到了終止條件。
        • 如果還沒達到終止條件,下一階段還會在分裂好的簇中選一個直徑最大的簇按剛纔的分類方法分裂。
  4. 代碼實現:

     import math
     import numpy as np
     import pylab as pl
     
     
     # 加載數據
     def loadData(filename):
         dataSet = np.loadtxt(filename, delimiter='\t', encoding="UTF-8-sig")
         return dataSet
     
     
     # 計算歐式距離
     def dist(X, Y):
         # X 代表座標(x1, x2)   Y 代表座標(y1, y2)
         return math.sqrt(math.pow(X[0] - Y[0], 2) + math.pow(X[1] - Y[1], 2))
     
     
     # 找到具有最大直徑的簇
     def find_Maxdis(M):
         avg_Dissimilarity = []  # 平均相異度數組
         max_Dissimilarity = -1  # 最大平均相異度
         numOrder = 0
         # M 爲 (n, n) 矩陣, 對每個點計算平均相異度
         for i in range(len(M)):
             dis = 0
             for j in range(len(M[i])):
                 if i != j:
                     dis += M[i][j]
             avg_Dissimilarity.append(dis / (len(M) - 1))
             # print(str(avg_Dissimilarity[i])+ "    " + str(i))
         # 在找到平均相異度的最大值
         for m in range(len(avg_Dissimilarity)):
             if max_Dissimilarity < avg_Dissimilarity[m]:
                 max_Dissimilarity = avg_Dissimilarity[m]
                 numOrder = m
         # print(str(max_Dissimilarity) + "    " + str(k))
     
         # 返回當前平均相異度最大的簇的序號和平均相異度
         return numOrder, max_Dissimilarity
     
     
     def DIANA(dataSet, k):
         '''第一步,找到具有最大直徑的簇,對簇中的每個點計算平均相異度 ["找出最突出的點"],
     	挑選一個最大平均相異度的點放入splinter group中, 剩餘點放在old party中.'''
         C = []  # 初始簇, 所有對象爲一個簇
         M = []  # 每個對象間的距離矩陣
         for ci in dataSet:
             # 先構造一維數組, 每一個對象爲一個一維數組
             c = []
             c.append(ci)
             # 再將一維數組加入到數組中, 便構成了二維數組.
             C.append(ci)
         for ci in dataSet:
             Mi = []
             for cj in dataSet:
                 Mi.append(dist(ci, cj))
             M.append(Mi)
         # 挑選一個最大平均相異度的點放入splinter group中, 剩餘點放在old party中.
         numOrder, max_Dissimilarity = find_Maxdis(M)
         splinter_group = []
         old_party = []
         C_num = list(range(len(dataSet)))
         splinter_group.append(numOrder)
         C_num.remove(numOrder)
         for num in C_num:
             old_party.append(num)
         '''第二步,在old party裏找出   
                             **到splinter group的距離**
                                 小於
                             **到old party的距離的點**
                         將該點放入splinter group中,
                 Repeat ["不停地找最突出的點加入splinter group"]
                 Until 沒有新的old party的點被分配給splinter group;
                 Splinter group 和old party爲被選中的簇分裂成的兩個簇,與其他簇一起組成新的簇集合
                 END'''
         i = 1
         while i != k:
             # 在old party裏找出**到splinter group的距離**小於**到old party的距離的點**
             dis_Old_Old = 0
             dis_Old_Splinter = 0
             for old in old_party:
                 print(splinter_group)
                 # print(old_party)
     
                 # 在old party裏先找到old party的距離---這裏指平均距離
                 for old_other in old_party:
                     # 自己到自己的距離爲零, 所以不做其它處理
                     dis_Old_Old += M[old][old_other]
                 dis_Old_Old = dis_Old_Old / (len(old_party)-1)
                 print("dis_Old_Old: " + str(dis_Old_Old))
     
                 # 在old party裏然後再找到splinter group的距離---這裏指平均距離
                 for splinter in splinter_group:
                     dis_Old_Splinter += M[old][splinter]
                 dis_Old_Splinter = dis_Old_Splinter / (len(splinter_group))
                 print("dis_Old_Splinter: " + str(dis_Old_Splinter))
     
                 # 比較後, 將滿足條件的點放在splinter group中
                 if dis_Old_Splinter < dis_Old_Old:
                     splinter_group.append(old)
                     print("每次加入到splinter_group的點: "+str(old))
                 else:
                     print("不滿足條件的點: " + str(old))
                 print("\n")
             i = i + 1
     
     
     if __name__ == "__main__":
         dataSet = loadData('test.txt')
         # print(dataSet)
         k = 2  # k代表預設的最終聚類簇數
         DIANA(dataSet, k)
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章