1. 程式人生 > >定量評估聚類效果

定量評估聚類效果

如果有了類別標籤,那麼聚類結果也可以像分類那樣計算準確率和召回率。但是不應該將分類標籤作為聚類結果的評價指標,除非你有相關的先驗知識或某種假設,知道這種分類類內差距更小。但是它還是給出了幾種評價標準。

7.9.1 調整蘭德係數 (Adjusted Rand index)

1. 數學原理

  蘭德係數(Rand index)需要給定實際類別資訊C,假設K是聚類結果,a表示在C與K中都是同類別的元素對數,b表示在C與K中都是不同類別的元素對數,則蘭德指數為:

1240

  對於以上公式,

  • 分子:屬性一致的樣本數,即同屬於這一類或都不屬於這一類。a是真實在同一類、預測也在同一類的樣本數;b是真實在不同類、預測也在不同類的樣本數;
  • 分母:任意兩個樣本為一類有多少種組合,是資料集中可以組成的總元素對數;
  • RI取值範圍為[0,1],值越大意味著聚類結果與真實情況越吻合。

  對於隨機結果,RI並不能保證分數接近零。為了實現“在聚類結果隨機產生的情況下,指標應該接近零”,調整蘭德係數(Adjusted rand index)被提出,它具有更高的區分度:

1240

  ARI取值範圍為[-1,1],值越大意味著聚類結果與真實情況越吻合。從廣義的角度來講,ARI衡量的是兩個資料分佈的吻合程度。

2. 優缺點

優點:

  1. 對任意數量的聚類中心和樣本數,隨機聚類的ARI都非常接近於0;
  2. 取值在[-1,1]之間,負數代表結果不好,越接近於1越好;
  3. 可用於聚類演算法之間的比較。

缺點:

  • ARI需要真實標籤

3. python程式碼實現

  1. labels_true, labels_pred = check_clusterings(labels_true, labels_pred)

  2. n_samples = labels_true.shape[0]

  3. classes = np.unique(labels_true)

  4. clusters = np.unique(labels_pred)

  5. # Special limit cases: no clustering since the data is not split;

  6. # or trivial clustering where each document is assigned a unique cluster.

  7. # These are perfect matches hence return 1.0.

  8. if (classes.shape[0] == clusters.shape[0] == 1 or classes.shape[0] == clusters.shape[0] == 0 or classes.shape[0] == clusters.shape[0] == len(labels_true)):

  9. return 1.0

  10. contingency = contingency_matrix(labels_true, labels_pred)

  11. # Compute the ARI using the contingency data

  12. sum_comb_c = sum(comb2(n_c) for n_c in contingency.sum(axis=1))

  13. sum_comb_k = sum(comb2(n_k) for n_k in contingency.sum(axis=0))

  14. sum_comb = sum(comb2(n_ij) for n_ij in contingency.flatten())

  15. prod_comb = (sum_comb_c * sum_comb_k) / float(comb(n_samples, 2))

  16. mean_comb = (sum_comb_k + sum_comb_c) / 2.

  17. return ((sum_comb - prod_comb) / (mean_comb - prod_comb))

4. metrics類使用方法

  設定已知先驗知識的標籤為labels_true,利用聚類演算法預測的樣本標籤為label_pred,Adjusted Rand index函式是在計算樣本預測值和真實值之間的相似度similarity:同屬於這一類或都不屬於這一類,而不考慮資料元素順序和歸一化。示例程式碼:

  1. >>> from sklearn import metrics

  2. >>> labels_true = [0, 0, 0, 1, 1, 1]

  3. >>> labels_pred = [0, 0, 1, 1, 2, 2]

  4. >>> metrics.adjusted_rand_score(labels_true, labels_pred)

  5. 0.24...

  我們也可以調整預測集label_pred中元素0和1的位置,以及將資料集中為2的屬性改名為3,其結果不受影響,示例程式碼:

  1. >>> labels_pred = [1, 1, 0, 0, 3, 3]

  2. >>> metrics.adjusted_rand_score(labels_true, labels_pred)

  3. 0.24...

  此外,調整adjusted_rand_score函式中labels_true和labels_pred的位置,對結果沒有影響,示例程式碼:

  1. >>> metrics.adjusted_rand_score(labels_pred, labels_true)

  2. 0.24...

  利用此函式評估模型最好的值為1,示例程式碼:

  1. >>> labels_pred = labels_true[:]

  2. >>> metrics.adjusted_rand_score(labels_true, labels_pred)

  3. 1.0

  評估模型最差的值(與labels_true不相關),其結果為負值或接近0值,示例程式碼:

  1. >>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]

  2. >>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]

  3. >>> metrics.adjusted_rand_score(labels_true, labels_pred)

  4. -0.12...

7.9.2 互資訊評分(Mutual Information based scores)

1. 數學原理

  互資訊(Mutual Information)也是用來衡量兩個資料分佈的吻合程度。假設U與V是對N個樣本標籤的分配情況,則兩種分佈的熵(熵表示的是不確定程度)分別為:

1240

1240


其中:

1240

1240


U與V之間的互資訊(MI)定義為:

1240


其中:

1240


標準化後的互資訊(Normalized mutual information)為:

1240


  不管標籤分配之間的“互資訊”的實際數量如何,互資訊或者標準化後的值不會因此而調整,而會隨著標籤(簇)數量的增加而增加。
互資訊的期望值可以用如下公式來計算:

1240


其中:

1240

1240


ai和bj分別對應著元素屬於Ui和Vj的數量。
  與ARI類似,調整互資訊( Adjusted mutual information)定義為:

1240


  利用基於互資訊的方法來衡量聚類效果需要實際類別資訊,MI與NMI取值範圍為[0,1],AMI取值範圍為[-1,1],它們都是值越大意味著聚類結果與真實情況越吻合。

2. 優缺點

  • 優點:除取值範圍在[0,1]之間,其他同ARI,可用於聚類模型選擇;
  • 缺點:需要先驗知識。

3. python程式碼實現

  1. if contingency is None:

  2. labels_true, labels_pred = check_clusterings(labels_true, labels_pred)

  3. contingency = contingency_matrix(labels_true, labels_pred)

  4. contingency = np.array(contingency, dtype='float')

  5. contingency_sum = np.sum(contingency)

  6. pi = np.sum(contingency, axis=1)

  7. pj = np.sum(contingency, axis=0)

  8. outer = np.outer(pi, pj)

  9. nnz = contingency != 0.0

  10. # normalized contingency

  11. contingency_nm = contingency[nnz]

  12. log_contingency_nm = np.log(contingency_nm)

  13. contingency_nm /= contingency_sum

  14. # log(a / b) should be calculated as log(a) - log(b) for

  15. # possible loss of precision

  16. log_outer = -np.log(outer[nnz]) + log(pi.sum()) + log(pj.sum())

  17. mi = (contingency_nm * (log_contingency_nm - log(contingency_sum))+ contingency_nm * log_outer)

  18. return mi.sum()

4. metrics類使用方法

  設定已知先驗知識的標籤為labels_true,利用聚類演算法預測的樣本標籤為label_pred,互資訊是衡量兩種預測的一致性,忽略排列的順序。互資訊評估有兩種方法,標準化的互資訊Normalized Mutual Information(NMI) 和調整後的互資訊Adjusted Mutual Information(AMI)。示例程式碼:

  1. >>> from sklearn import metrics

  2. >>> labels_true = [0, 0, 0, 1, 1, 1]

  3. >>> labels_pred = [0, 0, 1, 1, 2, 2]

  4. >>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)

  5. 0.22504...

  我們也可以調整預測集label_pred中元素0和1的位置,以及將資料集中為2的屬性改名為3,其結果不受影響,示例程式碼:

  1. >>> labels_pred = [1, 1, 0, 0, 3, 3]

  2. >>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)

  3. 0.22504..

  互資訊評分中mutual_info_score,adjusted_mutual_info_score和normalized_mutual_info_score函式其引數都是對稱的,交換的引數位置不會改變評分值,示例程式碼:

  1. >>> metrics.adjusted_mutual_info_score(labels_pred, labels_true)

  2. 0.22504...

  利用此函式評估模型最好的值為1,示例程式碼:

  1. >>> labels_pred = labels_true[:]

  2. >>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)

  3. 1.0

  4. >>> metrics.normalized_mutual_info_score(labels_true, labels_pred)

  5. 1.0

  評估模型最差的值(與labels_true不相關),其結果為非正值,示例程式碼:

  1. >>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]

  2. >>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]

  3. >>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)

  4. -0.10526...

7.9.3 同質性Homogeneity 完整性completeness 調和平均V-measure

1. 數學原理

  • 同質性homogeneity:每個群集只包含單個類的成員;
  • 完整性completeness:給定類的所有成員都分配給同一個群集。

  同質性和完整性分數基於以下公式得出:

1240

1240


  其中H(C|K)是給定給定簇賦值的類的條件熵,由以下公式求得:

1240


  H(C)是類熵,公式為:

1240


  其中,n是樣本總數,nc和nk分別屬於類c和類k的樣本數,而nc,k是從類c劃分到類k的樣本數量。
  條件熵H(K|C)和類熵H(K),根據以上公式對稱求得。
  V-measure是同質性homogeneity和完整性completeness的調和平均數,公式:

1240

2. 優缺點

優點:

  • 分數明確:從0到1反應出最差到最優的表現;
  • 解釋直觀:差的調和平均數可以在同質性和完整性方面做定性的分析;
  • 對簇結構不作假設:可以比較兩種聚類演算法如k均值演算法和譜聚類演算法的結果。

缺點:

  • 以前引入的度量在隨機標記方面沒有規範化,這意味著,根據樣本數,叢集和先驗知識,完全隨機標籤並不總是產生相同的完整性和均勻性的值,所得調和平均值V-measure也不相同。特別是,隨機標記不會產生零分,特別是當簇的數量很大時。

當樣本數大於一千,聚類數小於10時,可以安全地忽略該問題。對於較小的樣本量或更大數量的叢集,使用經過調整的指數(如調整蘭德指數)更為安全。

1240

  • 這些指標要求的先驗知識,在實踐中幾乎不可用或需要手動分配的人作註解者(如在監督學習環境中)。

3. sklearn實現方法

  sklearn.metrics類的homogeneity_score和completeness_score方法分別用來求得同質性和完整性分數,示例程式碼:

  1. >>> from sklearn import metrics

  2. >>> labels_true = [0, 0, 0, 1, 1, 1]

  3. >>> labels_pred = [0, 0, 1, 1, 2, 2]

  4. >>> metrics.homogeneity_score(labels_true, labels_pred)

  5. 0.66...

  6. >>> metrics.completeness_score(labels_true, labels_pred)

  7. 0.42...

  兩者的調和平均V-measure,示例程式碼:

  1. >>> metrics.v_measure_score(labels_true, labels_pred)

  2. 0.51...

  metrics類的homogeneity_completeness_v_measure融合了以上方法,分別能求得相關值,示例程式碼:

  1. >>> metrics.homogeneity_completeness_v_measure(labels_true, labels_pred)

  2. ...

  3. (0.66..., 0.42..., 0.51...)

  以下預測的評分略好,體現在同質性而非完整性,示例程式碼:

  1. >>> labels_true = [0, 0, 0, 1, 1, 1]

  2. >>> labels_pred = [0, 0, 0, 1, 2, 2]

  3. >>> metrics.homogeneity_completeness_v_measure(labels_true, labels_pred)

  4. ...

  5. (1.0, 0.68..., 0.81...)

7.9.4 Fowlkes-Mallows scores

  Fowlkes-Mallows指數是針對訓練集和驗證集資料之間求得的查全率和查準率的幾何平均值,其公式為:

1240


  示例程式碼:

  1. >>> from sklearn import metrics

  2. >>> labels_true = [0, 0, 0, 1, 1, 1]

  3. >>> labels_pred = [0, 0, 1, 1, 2, 2]

  4. >>>

  5. >>> metrics.fowlkes_mallows_score(labels_true, labels_pred)

  6. 0.47140...

7.9.5 輪廓係數 Silhouette Coefficient

  輪廓係數適用於實際類別資訊未知的情況。對於單個樣本,設a是與它同類別中其他樣本的平均距離,b是與它距離最近不同類別中樣本的平均距離,其輪廓係數為:

1240


  對於一個樣本集合,它的輪廓係數是所有樣本輪廓係數的平均值。
  輪廓係數的取值範圍是[-1,1],同類別樣本距離越相近不同類別樣本距離越遠,分數越高。
  示例程式碼:

  1. >>> from sklearn import metrics

  2. >>> from sklearn.metrics import pairwise_distances

  3. >>> from sklearn import datasets

  4. >>> dataset = datasets.load_iris()

  5. >>> X = dataset.data

  6. >>> y = dataset.target

  7. >>> import numpy as np

  8. >>> from sklearn.cluster import KMeans

  9. >>> kmeans_model = KMeans(n_clusters=3, random_state=1).fit(X)

  10. >>> labels = kmeans_model.labels_

  11. >>> metrics.silhouette_score(X, labels, metric='euclidean')

  12. ...

  13. 0.55...