輪廓係數(Silhouette Coefficient Index)
輪廓係數(Silhouette Coefficient Index)是一種聚類評估指標,用於評估數據聚類的效果。其取值範圍在[-1, 1]之間,指標值越大表示聚類結果聚類效果越好。
具體來說,輪廓係數既要考慮聚類結果的緊密性,又要考慮聚類結果之間的分離度。如果一個數據點與自己所屬的簇內的其他數據點的距離很小,但是與其他簇中的數據點的距離很大,就表示這個數據點所在的簇內緊密度高,簇間分離度大,那麼該數據點的輪廓係數就會越大。
總體來講,輪廓係數是更加全面的評估指標,因爲它不僅考慮到了簇內的緊密度,還考慮了簇間的分離度。所以,在評估聚類效果時,尤其是對於需要分析簇內分佈緊密而簇間分佈分散的數據,輪廓係數是一個比較好的評估指標。
silhouette_score是一種聚類算法效果評估指標,用於評估聚類結果的緊密度和分離度。其取值範圍爲[-1,1],分別表示聚類結果差、不確定和良好。silhouette_score 越接近1,表示聚類結果越好,silhouette_score 越接近-1,表示分類結果較差,不過也可以出現接近0的情況,這說明分類結果不明顯。
雖然silhouette_score值越接近1越好,但並不是說得到一個越高的silhouette_score就認爲結果一定更好。具體來說,還需結合實際場景需求、數據特點、聚類算法等多方面因素做出綜合判斷。
1.1 原理
對於聚類結果的輪廓係數,它實際上是樣本輪廓係數的平均值。這也就是說聚類樣本中的每個樣本點對應都有一個輪廓係數值,而總的輪廓係數則是所有樣本點輪廓係數的平均值。
數據樣本中一共包含有3個簇結構,對於最左邊這個簇中(圓形)的樣本點\(i\)來說,距離其最近的簇爲中間(方形)這個簇。現在定義樣本\(i\)到簇中每個樣本距離的均值爲\(a(i)\),到最近簇中每個樣本距離的均值爲\(b(i)\),即此時根據上圖所示的結果有:
對於同一個簇中的每個樣本點來說,距離自己最近的簇可能並不是同一個;同時,在尋找距離當前樣本點最近的簇結構時,計算的是當前樣本點到各個簇中心的最短距離,而不是計算當前樣本點所在簇的簇中心到其它每個簇中心的最短距離。
此時,樣本\(i\)的輪廓係數\(s(i)\)定義爲:
當\(a(i)\)越小而\(b(i)\)越大時,此時對應的情況是樣本\(i\)所在的簇中所有樣本點之間距離都比較近(簇內距離較小),樣本\(i\)所在的簇距離其最近簇的距離較遠(因爲此時樣本\(i\)所在的簇中簇內距離較小,所以樣本\(i\)到其它簇的距離可以近似地看做樣本\(i\)所在簇到其它簇之間的距離),所以\(s(i)\)此時也就越接近於1,即聚類效果越好。
當\(b(i)\)越小而\(a(i)\)越大時,此時對應的情況是樣本\(i\)所在的簇中所有樣本點之間距離都比較遠(簇內距離較大),樣本\(i\)所在的簇距離其最近簇的距離較近,所以\(s(i)\)此時也就越接近於-1,即聚類效果越差。
輪廓係數是通過對每個數據點計算這個點和它所在簇內其他數據點的相似度以及該點與其他簇內數據點的相似度,綜合計算得出的。計算方法如下:
-
對於一個數據點 \(i\),先計算它和簇內其他數據點的平均距離 \(a_i\)(簇內相似度)。
-
然後計算該點與不包含該點所在簇的其他簇內數據點的平均距離 \(b_i\)(簇間相似度),選取其中距離最小的那個作爲 \(i\) 的簇間平均距離。
-
最後,計算數據點 \(i\) 的輪廓係數 \(s_i = \frac{b_i - a_i}{\max(a_i, b_i)}\)。
將所有數據點的輪廓係數取平均值,即得到聚類算法的整體輪廓係數。
需要注意的是,若某個數據點所在簇的數據點數量小於等於1,則該點的輪廓係數爲0。
每個樣本點都有一個輪廓係數值
1.2 代碼
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
from sklearn.metrics import silhouette_score, silhouette_samples
def test_silhouette_score():
x, y = load_iris(return_X_y=True)
model = KMeans(n_clusters=3)
model.fit(x)
y_pred = model.predict(x)
# 計算輪廓分數: 所有樣本點的輪廓係數的平均值
score_mean = silhouette_score(x, y_pred)
# 計算所有樣本點的輪廓係數
score_all = silhouette_samples(x, y_pred)
print(f"輪廓係數 by sklearn: {score_mean}")
if __name__ == '__main__':
test_silhouette_score()
上面的代碼執行的結果是:score_mean是所有的輪廓係數分數的平均值,score_all是所有的輪廓係數分數
silhouette_score
是用來計算所有樣本輪廓係數平均值
silhouette_samples
是用來計算聚類模型中每個樣本的輪廓係數