1. 程式人生 > >K-Means算法原理

K-Means算法原理

運行 問題 數列 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算法原理