K-means算法性能評估及其優化


1、 SSE誤差平方和(Sum of Square due to Error):

聚類情況:

計算公式:

注:SSE參數計算的內容為當前迭代得到的中心位置到各自中心點簇的歐式距離總和,這個值越小表示當前的分類效果越好!

參數描述:

  • P表示點位置(x,y)。
  • Mi為中心點的位置。
  • SSE表示了,當前的分類情況的中心點到自身分類簇的點的位置的總和。

使用方法:

在聚類算法迭代的過程中,我們通過計算當前得到的中心點情況下的SSE值來評估現在的分類效果,如果SSE值在某次迭代之后大大減小就說明聚類過程基本完成,不需要太多次的迭代了,

Code:

 1 # K-means Algorithm processing the point
 2 Point_Total = 100 # 某一種類型的總點數
 3 Error_Threshold = 0.1
 4 
 5 Point_A = (4, 3) # 高斯二維分布中心點
 6 Point_S_A = (np.random.normal(Point_A[0], 1, Point_Total),np.random.normal(Point_A[1], 1, Point_Total)) # 構造高斯二維分布散點
 7 
 8 Point_B = (-3,2) # 高斯二維分布中心點
 9 Point_S_B = (np.random.normal(Point_B[0], 1, Point_Total),np.random.normal(Point_B[1], 1, Point_Total)) # 構造高斯二維分布散點
10 
11 Point_O = np.hstack((Point_S_A,Point_S_B)) # 所有的點合並在一起
12 
13 Origin_A = [Point_O[0][0],Point_O[1][0]]   # 取得K-means算法的起始分類點
14 Origin_B = [Point_O[0][20],Point_O[1][20]] # 設置K-means算法的起始分類點
15 
16 plt.figure("實時分類") # 創建新得顯示窗口
17 plt.ion() # 持續刷新當前窗口的內容,不需要使用plt.show()函數
18 plt.scatter(Point_O[0],Point_O[1],c='k') # 所有的初始數據顯示為黑色
19 plt.scatter(Origin_A[0],Origin_A[1],c='b',marker='D') # 顯示第一類分類點的位置
20 plt.scatter(Origin_B[0],Origin_B[1],c='r',marker='*') # 顯示第二類分類點的位置
21 
22 Status_A = False # 設置A類別分類未完成False
23 Status_B = False # 設置B類別分類未完成False
24 
25 CiSum_List = []
26 while not Status_A and not Status_B: # 開始分類
27         Class_A = [] # 分類結果保存空間
28         Class_B = [] # 分類結果保存空間
29         print("Seperating the point...")
30         CASum = 0
31         CBSum = 0
32         for i in range(Point_Total*2): # 開始計算分類點到所有點的歐式距離(注意只需要使用平方和即可,不需要sqrt浪費時間)
33                 d_A = np.power(Origin_A[0]-Point_O[0][i], 2) + np.power(Origin_A[1]-Point_O[1][i], 2) # 計算距離
34                 d_B = np.power(Origin_B[0]-Point_O[0][i], 2) + np.power(Origin_B[1]-Point_O[1][i], 2) # 計算距離
35                 if d_A > d_B:
36                         Class_B.append((Point_O[0][i],Point_O[1][i])) # 將距離當前點較近的數據點包含在自己的空間中
37                         plt.scatter(Point_O[0][i],Point_O[1][i],c='r') # 更新新的點的顏色
38                         CBSum += d_B
39                 else:
40                         Class_A.append((Point_O[0][i],Point_O[1][i])) # 將距離當前點較近的數據點包含在自己的空間中
41                         plt.scatter(Point_O[0][i],Point_O[1][i],c='b') # 更新新的點的顏色
42                         CASum =+ d_A
43                 plt.pause(0.08) # 顯示暫停0.08s
44 
45         CiSum = CASum + CBSum
46         CiSum_List.append(CiSum) # 統計計算SSE的值
47 
48         A_Shape = np.shape(Class_A)[0] # 取得當前分類為A集合的點的總數
49         B_Shape = np.shape(Class_B)[0] # 取得當前分類為B集合的點的總數
50         Temp_x = 0
51         Temp_y = 0
52         for p in Class_A: # 計算A集合的質心
53                 Temp_x += p[0]
54                 Temp_y += p[1]
55         error_x = np.abs(Origin_A[0] - Temp_x/A_Shape) # 求平均得到重心-質心
56         error_y = np.abs(Origin_A[1] - Temp_y/A_Shape)
57         print("The error Of A:(",error_x,",",error_y,")") # 顯示當前位置和質心的誤差
58         if error_x < Error_Threshold and error_y < Error_Threshold:
59                 Status_A = True # 誤差滿足設定的誤差閾值范圍,將A集合的狀態設置為OK-True
60         else: 
61                 Origin_A[0] = Temp_x/A_Shape # 求平均得到重心-質心
62                 Origin_A[1] = Temp_y/A_Shape
63                 plt.scatter(Origin_A[0],Origin_A[1],c='g',marker='*') # the Map-A
64                 print("Get New Center Of A:(",Origin_A[0],",",Origin_A[1],")") # 顯示中心坐標點
65 
66         Temp_x = 0
67         Temp_y = 0
68         for p in Class_B: # 計算B集合的質心
69                 Temp_x += p[0]
70                 Temp_y += p[1]
71         error_x = np.abs(Origin_B[0] - Temp_x/B_Shape) # 求平均得到重心-質心
72         error_y = np.abs(Origin_B[1] - Temp_y/B_Shape)
73         print("The error Of B:(",error_x,",",error_y,")")
74         if error_x < Error_Threshold and error_y < Error_Threshold:
75                 Status_B = True # 誤差滿足設定的誤差閾值范圍,將B集合的狀態設置為OK-True
76         else: 
77                 Origin_B[0] = Temp_x/B_Shape # 求平均得到重心-質心
78                 Origin_B[1] = Temp_y/B_Shape
79                 plt.scatter(Origin_B[0],Origin_B[1],c='y',marker='x') # the Map-B
80                 print("Get New Center Of B:(",Origin_B[0],",",Origin_B[1],")") # 顯示中心坐標點
81 
82 print("Finished the divide!")
83 print(CiSum_List) # 統計結果
84 plt.figure("真實分類")
85 plt.scatter(Point_S_A[0],Point_S_A[1]) # The Map-A
86 plt.scatter(Point_S_B[0],Point_S_B[1]) # The Map-A
87 plt.show()
88 
89 plt.figure("SSE Res")
90 plt.plot(CiSum_List) # 繪制SSE結果圖
91 
92 plt.pause(15)
93 plt.show()
View Code

結果:

2、 SC系數(Silhouette Cofficient)輪廓系數法:

評估標准描述:結合了聚類的凝聚度(Cohesion)和分離度(Separation),用於評估聚類算法的效果。

參數描述:

  • a表示C1簇中的某一個樣本點Xi到自身簇中其他樣本點的距離總和的平均值。
  • bC2表示樣本點Xi 到C2簇中所有樣本點的距離總和的平均值。
  • bC3表示樣本點Xi 到C3簇中所有樣本點的距離總和的平均值。
  • 我們定義b = min(bC2 ,bC3)

計算公式:

  • a:樣本Xi到同一簇內其他點不相似程度的平均值
  • b:樣本Xi到其他簇的平均不相似程度的最小值

使用方法:

每次聚類之后,每一個樣本點都會得到一個輪廓系數,當S的取值越靠近1,當前點與周圍簇距離較遠,結果非常好。

當S的取值為0,說明當前點可能處在兩個簇的邊界上。

當S的取值為負數時,可能這個點唄誤分了。

求出所有樣本點的輪廓系數之后再求平均值就得到了平均輪廓系數,平均輪廓系數越大,簇內樣本距離越近,簇間樣本距離越遠,聚類效果越好。

Code:

3、CH系數(Calinski Harabasz Index)輪廓系數法:

參數描述:

  • C1:簇1的中心位置
  • C2:簇2的中心位置
  • C3:簇3的中心位置
  • Xi:簇當中的某一個樣本點
  • X平均:所有簇當中的樣本點的中心位置

計算公式:

 

使用方法:

Code:

4、總結:

在我們考量當前的聚類算法的K值選擇的問題是,我們會總和匯總上述三種衡量系數來共同確定K值的選擇,使得我們選擇最好的K值。

如下實例過程,我們來選擇合適的K值:

Code:

Result:

分析:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM