用scikit-learn學習譜聚類

劉建平Pinard發表於2016-12-30

    在譜聚類(spectral clustering)原理總結中,我們對譜聚類的原理做了總結。這裡我們就對scikit-learn中譜聚類的使用做一個總結。

1. scikit-learn譜聚類概述

    在scikit-learn的類庫中,sklearn.cluster.SpectralClustering實現了基於Ncut的譜聚類,沒有實現基於RatioCut的切圖聚類。同時,對於相似矩陣的建立,也只是實現了基於K鄰近法和全連線法的方式,沒有基於$\epsilon$-鄰近法的相似矩陣。最後一步的聚類方法則提供了兩種,K-Means演算法和 discretize演算法。

    對於SpectralClustering的引數,我們主要需要調參的是相似矩陣建立相關的引數和聚類類別數目,它對聚類的結果有很大的影響。當然其他的一些引數也需要理解,在必要時需要修改預設引數。

2. SpectralClustering重要引數與調參注意事項

    下面我們就對SpectralClustering的重要引數做一個介紹,對於調參的注意事項會一起介紹。

    1)n_clusters:代表我們在對譜聚類切圖時降維到的維數(原理篇第7節的$k_1$),同時也是最後一步聚類演算法聚類到的維數(原理篇第7節的$k_2$)。也就是說scikit-learn中的譜聚類對這兩個引數統一到了一起。簡化了調參的引數個數。雖然這個值是可選的,但是一般還是推薦調參選擇最優引數。

    2) affinity: 也就是我們的相似矩陣的建立方式。可以選擇的方式有三類,第一類是 'nearest_neighbors'即K鄰近法。第二類是'precomputed'即自定義相似矩陣。選擇自定義相似矩陣時,需要自己呼叫set_params來自己設定相似矩陣。第三類是全連線法,可以使用各種核函式來定義相似矩陣,還可以自定義核函式。最常用的是內建高斯核函式'rbf'。其他比較流行的核函式有‘linear’即線性核函式, ‘poly’即多項式核函式, ‘sigmoid’即sigmoid核函式。如果選擇了這些核函式, 對應的核函式引數在後面有單獨的引數需要調。自定義核函式我沒有使用過,這裡就不多講了。affinity預設是高斯核'rbf'。一般來說,相似矩陣推薦使用預設的高斯核函式。

    3) 核函式引數gamma: 如果我們在affinity引數使用了多項式核函式 'poly',高斯核函式‘rbf’, 或者'sigmoid'核函式,那麼我們就需要對這個引數進行調參。

    多項式核函式中這個引數對應$K(x, z) = (\gamma x \bullet z  + r)^d$中的$\gamma$。一般需要通過交叉驗證選擇一組合適的$\gamma, r, d$

    高斯核函式中這個引數對應$K(x, z) = exp(-\gamma||x-z||^2)$中的$\gamma$。一般需要通過交叉驗證選擇合適的$\gamma$

    sigmoid核函式中這個引數對應$K(x, z) = tanh(\gamma x \bullet z  + r)$中的$\gamma$。一般需要通過交叉驗證選擇一組合適的$\gamma, r$

    $\gamma$預設值為1.0,如果我們affinity使用'nearest_neighbors'或者是'precomputed',則這麼引數無意義。

    4)核函式引數degree:如果我們在affinity引數使用了多項式核函式 'poly',那麼我們就需要對這個引數進行調參。這個引數對應$K(x, z) = (\gamma x \bullet z  + r)^d$中的$d$。預設是3。一般需要通過交叉驗證選擇一組合適的$\gamma, r, d$

    5)核函式引數coef0: 如果我們在affinity引數使用了多項式核函式 'poly',或者sigmoid核函式,那麼我們就需要對這個引數進行調參。

    多項式核函式中這個引數對應$K(x, z) = (\gamma x \bullet z  + r)^d$中的$r$。一般需要通過交叉驗證選擇一組合適的$\gamma, r, d$

    sigmoid核函式中這個引數對應$K(x, z) = tanh(\gamma x \bullet z  + r)$中的$r$。一般需要通過交叉驗證選擇一組合適的$\gamma, r$

    coef0預設為1.

    6)kernel_params:如果affinity引數使用了自定義的核函式,則需要通過這個引數傳入核函式的引數。

    7 )n_neighbors: 如果我們affinity引數指定為'nearest_neighbors'即K鄰近法,則我們可以通過這個引數指定KNN演算法的K的個數。預設是10.我們需要根據樣本的分佈對這個引數進行調參。如果我們affinity不使用'nearest_neighbors',則無需理會這個引數。

    8)eigen_solver:1在降維計算特徵值特徵向量的時候,使用的工具。有 None, ‘arpack’, ‘lobpcg’, 和‘amg’4種選擇。如果我們的樣本數不是特別大,無需理會這個引數,使用''None暴力矩陣特徵分解即可,如果樣本量太大,則需要使用後面的一些矩陣工具來加速矩陣特徵分解。它對演算法的聚類效果無影響。

    9)eigen_tol:如果eigen_solver使用了arpack’,則需要通過eigen_tol指定矩陣分解停止條件。

    10)assign_labels:即最後的聚類方法的選擇,有K-Means演算法和 discretize演算法兩種演算法可以選擇。一般來說,預設的K-Means演算法聚類效果更好。但是由於K-Means演算法結果受初始值選擇的影響,可能每次都不同,如果我們需要演算法結果可以重現,則可以使用discretize。

    11)n_init:即使用K-Means時用不同的初始值組合跑K-Means聚類的次數,這個和K-Means類裡面n_init的意義完全相同,預設是10,一般使用預設值就可以。如果你的n_clusters值較大,則可以適當增大這個值。

    從上面的介紹可以看出,需要調參的部分除了最後的類別數n_clusters,主要是相似矩陣affinity的選擇,以及對應的相似矩陣引數。當我選定一個相似矩陣構建方法後,調參的過程就是對應的引數交叉選擇的過程。對於K鄰近法,需要對n_neighbors進行調參,對於全連線法裡面最常用的高斯核函式rbf,則需要對gamma進行調參。     

3.SpectralClustering例項

    這裡我們用一個例子講述下SpectralClustering的聚類。我們選擇最常用的高斯核來建立相似矩陣,用K-Means來做最後的聚類。

    完整程式碼參見我的github: https://github.com/ljpzzz/machinelearning/blob/master/classic-machine-learning/spectral_cluster.ipynb

    首先我們生成500個個6維的資料集,分為5個簇。由於是6維,這裡就不視覺化了,程式碼如下:

import numpy as np
from sklearn import datasets
X, y = datasets.make_blobs(n_samples=500, n_features=6, centers=5, cluster_std=[0.4, 0.3, 0.4, 0.3, 0.4], random_state=11)

    接著我們看看預設的譜聚類的效果:

from sklearn.cluster import SpectralClustering
y_pred = SpectralClustering().fit_predict(X)
from sklearn import metrics
print "Calinski-Harabasz Score", metrics.calinski_harabaz_score(X, y_pred) 

    輸出的Calinski-Harabasz分數為:

Calinski-Harabasz Score 14908.9325026  

    由於我們使用的是高斯核,那麼我們一般需要對n_clusters和gamma進行調參。選擇合適的引數值。程式碼如下:

for index, gamma in enumerate((0.01,0.1,1,10)):
    for index, k in enumerate((3,4,5,6)):
        y_pred = SpectralClustering(n_clusters=k, gamma=gamma).fit_predict(X)
        print "Calinski-Harabasz Score with gamma=", gamma, "n_clusters=", k,"score:", metrics.calinski_harabaz_score(X, y_pred) 

    輸出如下:

Calinski-Harabasz Score with gamma= 0.01 n_clusters= 3 score: 1979.77096092
Calinski-Harabasz Score with gamma= 0.01 n_clusters= 4 score: 3154.01841219
Calinski-Harabasz Score with gamma= 0.01 n_clusters= 5 score: 23410.63895
Calinski-Harabasz Score with gamma= 0.01 n_clusters= 6 score: 19303.7340877
Calinski-Harabasz Score with gamma= 0.1 n_clusters= 3 score: 1979.77096092
Calinski-Harabasz Score with gamma= 0.1 n_clusters= 4 score: 3154.01841219
Calinski-Harabasz Score with gamma= 0.1 n_clusters= 5 score: 23410.63895
Calinski-Harabasz Score with gamma= 0.1 n_clusters= 6 score: 19427.9618944
Calinski-Harabasz Score with gamma= 1 n_clusters= 3 score: 687.787319232
Calinski-Harabasz Score with gamma= 1 n_clusters= 4 score: 196.926294549
Calinski-Harabasz Score with gamma= 1 n_clusters= 5 score: 23410.63895
Calinski-Harabasz Score with gamma= 1 n_clusters= 6 score: 19384.9657724
Calinski-Harabasz Score with gamma= 10 n_clusters= 3 score: 43.8197355672
Calinski-Harabasz Score with gamma= 10 n_clusters= 4 score: 35.2149370067
Calinski-Harabasz Score with gamma= 10 n_clusters= 5 score: 29.1784898767
Calinski-Harabasz Score with gamma= 10 n_clusters= 6 score: 47.3799111856

    可見最好的n_clusters是5,而最好的高斯核引數是1或者0.1.

    我們可以看看不輸入可選的n_clusters的時候,僅僅用最優的gamma為0.1時候的聚類效果,程式碼如下:

y_pred = SpectralClustering(gamma=0.1).fit_predict(X)
print "Calinski-Harabasz Score", metrics.calinski_harabaz_score(X, y_pred) 

    輸出為:

Calinski-Harabasz Score 14950.4939717

    可見n_clusters一般還是調參選擇比較好。

 

(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com)     

相關文章