機器學習(聚類十)——譜聚類及代碼實現

譜聚類是基於譜圖理論基礎上的一種聚類方法,與傳統的聚類方法相比:具有在任意形狀的樣本空間上聚類並且收斂於全局最優解的優點。(但效率不高,實際工作中用的比較少)

譜聚類

通過對樣本數據的拉普拉斯矩陣特徵向量進行聚類,從而達到對樣本數據進行聚類的目的;其本質是將聚類問題轉換爲圖的最優劃分問題,是一種點對聚類算法。

譜聚類算法將數據集中的每個對象看做圖的頂點 V,將頂點間的相似度量化爲相應頂點連接邊E的權值 w,這樣就構成了一個基於相似度的無向加權圖 G(V,E),於是聚類問題就轉換爲圖的劃分問題。基於圖的最優劃分規則就是子圖內的相似度最大,子圖間的相似度最小

步驟
譜聚類的構建過程主要包含以下幾個步驟

  • 構建表示對象相似度的矩陣 W
  • 構建度矩陣 D(對角矩陣)
  • 構建拉普拉斯矩陣 L(有個特點:行累加=0)
  • 計算矩陣L的前 k 個特徵值的特徵向量(k 個列向量)
  • 將k個列向量組成矩陣 U (Un×k)\quad \left( U_{n×k}\right)
  • 對矩陣 U 中的 n 行數據利用 K-means 或其它經典聚類算法進行聚類得出最終結果

拉普拉斯矩陣及變形
W=(wij)i,j=1,...,nW=(w_{ij}) \quad i,j=1,...,n

D=(i=1nw1j00000i=1nwij0000i=1nwnj)D= \begin{pmatrix} \sum_{i=1}^n w_{1j} & 0 & 0 & 0 \\ \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \sum_{i=1}^n w_{ij} & 0\\ 0 & 0 & 0 & \sum_{i=1}^n w_{nj} \end{pmatrix}

L=DWL=D-W

  • 拉普拉斯矩陣(算法默認使用的是拉普拉斯矩陣)
    L=DWL=D-W
  • 對稱拉普拉斯矩陣
    Lsym=D12(DW)D12=ID12WD12L_{sym}=D^{−\frac{1}{2}} (D−W) D^{−\frac{1}{2}}=I−D^{−\frac{1}{2}} WD^{−\frac{1}{2}}
  • 隨機遊走拉普拉斯矩陣
    Lrw=D1(DW)L_rw=D^{−1} (D−W)

應用場景
圖形聚類、計算機視覺、非凸球形數據聚類等

面臨的問題

  • 相似度矩陣的構建問題(比較難):業界一般使用高斯相似函數或者k近鄰來作爲相似度量,一般建議 使用k近鄰的方式來計算相似度權值
  • 聚類數目的給定
  • 如何選擇特徵向量(矩陣一大,求特徵向量的難度會比較高)
  • 如何提高譜聚類的執行效率

代碼實現

使用scikit的相關API創建模擬數據,然後使用譜聚類算法進行數據聚類操作,並比較算法在不同參數情況下的聚類效果。

API

sklearn.cluster.spectral_clustering(affinity, n_clusters=8, n_components=None, eigen_solver=None, random_state=None, n_init=10, eigen_tol=0.0, assign_labels=‘kmeans’)

參數

  • affinity:相似度矩陣構建方式
  • assign_labels:上面說的U的構建方式

代碼

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
import warnings
from sklearn.cluster import spectral_clustering#引入譜聚類
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import euclidean_distances

## 設置屬性防止中文亂碼及攔截異常信息
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False

warnings.filterwarnings('ignore', category=FutureWarning)

### 創建模擬數據
N = 1000
centers = [[1, 2], [-1, -1], [1, -1], [-1, 1]]
#符合高斯分佈的數據集
data1, y1 = ds.make_blobs(N, n_features=2, centers=centers, cluster_std=(0.75,0.5,0.3,0.25), random_state=0)
data1 = StandardScaler().fit_transform(data1)
dist1 = euclidean_distances(data1, squared=True)
# 權重計算公式
affinity_params1 = map(lambda x: (x,np.exp(-dist1 ** 2 / (x ** 2)) + 1e-6), np.logspace(-2,0,6))

# 數據2
#圓形數據集
t = np.arange(0, 2 * np.pi, 0.1)
data2_1 = np.vstack((np.cos(t), np.sin(t))).T
data2_2 = np.vstack((2*np.cos(t), 2*np.sin(t))).T
data2_3 = np.vstack((3*np.cos(t), 3*np.sin(t))).T
data2 = np.vstack((data2_1, data2_2, data2_3))
y2 = np.vstack(([0] * len(data2_1), [1] * len(data2_2), [2] * len(data2_3)))
## 數據2的參數
dist2 = euclidean_distances(data2, squared=True)
affinity_params2 = map(lambda x: (x, np.exp(-dist2 ** 2 / (x ** 2)) + 1e-6), np.logspace(-2,0,6))

datasets = [(data1, y1, affinity_params1), (data2, y2, affinity_params2)]

def expandBorder(a, b):
    d = (b - a) * 0.1
    return a-d, b+d
colors = ['r', 'g', 'b', 'y']
cm = mpl.colors.ListedColormap(colors)

for i,(X, y, params) in enumerate(datasets):
    x1_min, x2_min = np.min(X, axis=0)
    x1_max, x2_max = np.max(X, axis=0)
    x1_min, x1_max = expandBorder(x1_min, x1_max)
    x2_min, x2_max = expandBorder(x2_min, x2_max)
    n_clusters = len(np.unique(y))
    plt.figure(figsize=(12, 8), facecolor='w')
    plt.suptitle(u'譜聚類--數據%d' % (i+1), fontsize=20)
    plt.subplots_adjust(top=0.9,hspace=0.35)
    
    for j,param in enumerate(params):
        sigma,af = param
        #譜聚類的建模
        ## af: 指定相似度矩陣構造方式(就是相似度矩陣)
        y_hat = spectral_clustering(af, n_clusters=n_clusters, assign_labels='kmeans', random_state=28)
        unique_y_hat = np.unique(y_hat)
        n_clusters = len(unique_y_hat) - (1 if -1 in y_hat else 0)
        print ("類別:",unique_y_hat,";聚類簇數目:",n_clusters)
        
        ## 開始畫圖
        plt.subplot(3,3,j+1)
        for k, col in zip(unique_y_hat, colors):
            cur = (y_hat == k)
            plt.scatter(X[cur, 0], X[cur, 1], s=40, c=col, edgecolors='k')
        plt.xlim((x1_min, x1_max))
        plt.ylim((x2_min, x2_max))
        plt.grid(True)
        plt.title('$\sigma$ = %.2f ,聚類簇數目:%d' % (sigma, n_clusters), fontsize=16)

    plt.subplot(3,3,7)
    plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=cm, edgecolors='none')
    plt.xlim((x1_min, x1_max))
    plt.ylim((x2_min, x2_max))
    plt.title('原始數據,聚類簇數目:%d' % len(np.unique(y)))
    plt.grid(True)
    plt.show()  

類別: [0 1 2 3] ;聚類簇數目: 4
類別: [0 1 2 3] ;聚類簇數目: 4
類別: [0 1 2 3] ;聚類簇數目: 4
類別: [0 1 2 3] ;聚類簇數目: 4
類別: [0 1 2 3] ;聚類簇數目: 4
類別: [0 1 2 3] ;聚類簇數目: 4

在這裏插入圖片描述

類別: [0 1 2] ;聚類簇數目: 3
類別: [0 1 2] ;聚類簇數目: 3
類別: [0 1 2] ;聚類簇數目: 3
類別: [0 1 2] ;聚類簇數目: 3
類別: [0 1 2] ;聚類簇數目: 3
類別: [0 1 2] ;聚類簇數目: 3

在這裏插入圖片描述
上面提到“affinity:相似度矩陣構建方式”,可以使用高斯(相似度矩陣的構建問題,業界一般使用高斯相似函數或者k近鄰來作爲相似度量。)σ是高斯相似函數中的值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章