K-Means算法原理
阿新 • • 發佈:2018-10-14
運行 問題 數列 12c another row 文件 cli 讀取數據
原理
給定樣本集,k-means算法得到聚類,使得下面平方誤差最小
其中表示聚類的中心點。
實現
上式最小化是一個NP難問題,實際上采用EM算法可以求得近似解。算法偽代碼如下
輸入:,聚類數量k
從D中隨機選擇k個樣本點作為k個聚類的中心
repeat
循環所有樣本點,把樣本點劃分到最近的聚類中:arg min||x - ui||
更新聚類中心:ui = (∑x) / n
util 聚類中心不再變化
輸出:
實例
sklearn已經實現上述算法,測試代碼如下
import pandas as pd from matplotlib import pyplot as plt from sklearn.cluster import k_means # 1、讀取數據文件 df = pd.read_csv("data.csv", header=0) df.head() # 2、原始文件畫圖 X = df[‘x‘] y = df[‘y‘] plt.scatter(X, y) plt.show() # 3、k-means分為三類 model = k_means(df, n_clusters=3) print(model) # 4、分類後畫圖 cluster_centers = model[0] cluster_labels = model[1] plt.scatter(X, y, c=cluster_labels) for center in cluster_centers: plt.scatter(center[0], center[1], marker="p", edgecolors="red") plt.show()
k_means計算得到的model包含三部分
(1)各個聚類的中心
(2)樣本點的類別數組
(3)所有樣本點到各自聚類中心的距離平方和
運行結果如下
k值的確定
當我們不知道樣本有幾類時,可以采用以下兩種方式確定最優k值
1、肘部法則
對於上面k_means方法返回值得第三部分,樣本點到聚類中心點的距離平方和s。很明顯,k = m時(m表示樣本數量),s = 0,s隨著k的增加而減小,s減小幅度隨著k增加而減小。我們找到s變化率改變最大時對應的k值(即肘部)作為最優k值。代碼如下
# 肘部法則 index = [] # 橫坐標數組 inertia = [] # 縱坐標數組 # K 從 1~ 10 聚類 for i in range(9): model = k_means(df, n_clusters=i + 1) index.append(i + 1) inertia.append(model[2]) # 繪制折線圖 plt.plot(index, inertia, "-o") plt.show()
運行結果如下,顯然k = 3是最優值
2、輪廓系數
假設我們已經通過一定算法,將待分類數據進行了聚類,得到k個簇 。對於其中的一個點 i 來說:
a(i) = i向量到它所屬簇中其它點的距離平均值
b(i) = i向量到所有其他簇的點的平均距離的最小值
那麽點i的輪廓系數就為:
可見輪廓系數的值是介於 [-1,1] ,越趨近於1代表內聚度和分離度都相對較優。將所有點的輪廓系數求平均,就是該聚類結果總的輪廓系數。
代碼實現如下
#輪廓系數 from sklearn.metrics import silhouette_score # 導入輪廓系數計算模塊 index2 = [] # 橫坐標 silhouette = [] # 輪廓系數列表 # K 從 2 ~ 10 聚類 for i in range(8): model = k_means(df, n_clusters=i + 2) index2.append(i + 2) silhouette.append(silhouette_score(df, model[1])) print(silhouette) # 輸出不同聚類下的輪廓系數 # 繪制折線圖 plt.plot(index2, silhouette, "-o") plt.show()
實驗結果如下,顯然k = 3是最優值。
K-Means算法原理