【機器學習】--譜聚類從初始到應用

LHBlog發表於2018-04-06

一、前述

    譜聚類(spectral clustering)是一種基於圖論的聚類方法,主要思想是把所有的資料看做空間中的點,這些點之間可以用邊連線起來。距離較遠(或者相似度較低)的兩個點之間的邊權重值較低而距離較近(或者相似度較高)的兩個點之間的邊權重值較高,通過對所有資料點組成的圖進行切圖,讓切圖後不同的子圖間邊權重和儘可能的低,而子圖內的邊權重和儘可能的高,從而達到聚類的目的。

二、具體原理

1、優點
譜聚類相較於前面講到的最最傳統的k-means聚類方法,譜聚類又具有許多的優點:

1.只需要待聚類點之間的相似度矩陣就可以做聚類了。

2.對於不規則的資料(或者說是離群點)不是那麼敏感

3.k-means聚類演算法比較適合於凸資料集資料集內的任意兩點之間的連線都在該資料集以內,簡單理解就是圓形,可能不準確),而譜聚類則比較通用。

2、相關概念

相似度矩陣S的構建

構建相似度的矩陣的過程中,可以使用歐氏距離、餘弦相似度、高斯相似度等來計算資料點之間的相似度,選用哪個要根據你自己的實際情況來。不過在譜聚類中推薦使用的是高斯相似度,但是我在我的工程中使用的是餘弦相似度。

拉普拉斯矩陣
 它的定義很簡單,拉普拉斯矩陣。是度矩陣,也就是相似度矩陣的每一行(或者每一列)加和得到的一個對角矩陣。W就是圖的鄰接矩陣。

相似矩陣

鄰接矩陣它是由任意兩點之間的權重值組成的矩陣通常我們可以自己輸入權重,但是在譜聚類中,我們只有資料點的定義,並沒有直接給出這個鄰接矩陣,那麼怎麼得到這個鄰接矩陣呢?
基本思想是,距離較遠的兩個點之間的邊權重值較低,而距離較近的兩個點之間的邊權重值較高,不過這僅僅是定性,我們需要定量的權重值。一般來說我們可以通過樣本點距離度量的相似矩陣來獲得鄰接矩陣。

構建鄰接矩陣的方法有三類。-鄰近法,K鄰近法和全連線法。

    對於-鄰近法,它設定了一個距離閾值,然後用歐式距離度量任意兩點和的距離。即相似矩陣的,  然後根據和的大小關係,來定義鄰接矩陣如下:

    從上式可見,兩點間的權重要不就是,要不就是0,沒有其他的資訊了。距離遠近度量很不精確,因此在實際應用中,我們很少使用-鄰近法。

    第二種定義鄰接矩陣的方法是K鄰近法,利用KNN演算法遍歷所有的樣本點,取每個樣本最近的k個點作為近鄰,只有和樣本距離最近的k個點之間的。但是這種方法會造成重構之後的鄰接矩陣W非對稱,我們後面的演算法需要對稱鄰接矩陣。為了解決這種問題,一般採取下面兩種方法之一:

    第一種K鄰近法是隻要一個點在另一個點的K近鄰中,則保留

    第二種K鄰近法是必須兩個點互為K近鄰中,才能保留

    第三種定義鄰接矩陣的方法是全連線法,相比前兩種方法,第三種方法所有的點之間的權重值都大於0,因此稱之為全連線法。可以選擇不同的核函式來定義邊權重,常用的有多項式核函式,高斯核函式和Sigmoid核函式。最常用的是高斯核函式RBF,此時相似矩陣和鄰接矩陣相同:
    在實際的應用中,使用第三種全連線法來建立鄰接矩陣是最普遍的,而在全連線法中使用高斯徑向核RBF是最普遍的。

3、演算法流程:

               輸入:樣本集D=,相似矩陣的生成方式, 降維後的維度, 聚類方法,聚類後的維度

    輸出: 簇劃分

    1) 根據輸入的相似矩陣的生成方式構建樣本的相似矩陣S

    2)根據相似矩陣S構建鄰接矩陣W,構建度矩陣D

    3)計算出拉普拉斯矩陣L

    4)求L的最小的個特徵值所各自對應的特徵向量

    6) 將特徵向量組成維的特徵矩陣F

    7)對F中的每一行作為一個維的樣本,共n個樣本,用輸入的聚類方法進行聚類,聚類維數為。

    8)得到簇劃分

4、總結

譜聚類演算法是一個使用起來簡單,但是講清楚卻不是那麼容易的演算法,它需要你有一定的數學基礎。如果你掌握了譜聚類,相信你會對矩陣分析,圖論有更深入的理解。同時對降維裡的主成分分析也會加深理解。   

譜聚類演算法的主要優點有:
    1)譜聚類只需要資料之間的相似度矩陣,因此對於處理稀疏資料的聚類很有效。這點傳統聚類演算法比如K-Means很難做到
    2)由於使用了降維,因此在處理高維資料聚類時的複雜度比傳統聚類演算法好
譜聚類演算法的主要缺點有:
    1)如果最終聚類的維度非常高,則由於降維的幅度不夠,譜聚類的執行速度和最後的聚類效果均不好。
    2) 聚類效果依賴於相似矩陣,不同的相似矩陣得到的最終聚類效果可能很不同。

三、程式碼

 

 

# !/usr/bin/python
# -*- coding:utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from sklearn.cluster import spectral_clustering
from sklearn.metrics import euclidean_distances


def expand(a, b):
    d = (b - a) * 0.1
    return a-d, b+d


if __name__ == "__main__":
    matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
    matplotlib.rcParams['axes.unicode_minus'] = False

    t = np.arange(0, 2*np.pi, 0.1)
    data1 = np.vstack((np.cos(t), np.sin(t))).T
    data2 = np.vstack((2*np.cos(t), 2*np.sin(t))).T
    data3 = np.vstack((3*np.cos(t), 3*np.sin(t))).T
    data = np.vstack((data1, data2, data3))

    n_clusters = 3
    m = euclidean_distances(data, squared=True)
    sigma = np.median(m)

    plt.figure(figsize=(12, 8), facecolor='w')
    plt.suptitle(u'譜聚類', fontsize=20)
    clrs = plt.cm.Spectral(np.linspace(0, 0.8, n_clusters))
    for i, s in enumerate(np.logspace(-2, 0, 6)):
        print(s)
        af = np.exp(-m ** 2 / (s ** 2)) + 1e-6
        y_hat = spectral_clustering(af, n_clusters=n_clusters, assign_labels='kmeans', random_state=1)
        plt.subplot(2, 3, i+1)
        for k, clr in enumerate(clrs):
            cur = (y_hat == k)
            plt.scatter(data[cur, 0], data[cur, 1], s=40, c=clr, edgecolors='k')
        x1_min, x2_min = np.min(data, axis=0)
        x1_max, x2_max = np.max(data, axis=0)
        x1_min, x1_max = expand(x1_min, x1_max)
        x2_min, x2_max = expand(x2_min, x2_max)
        plt.xlim((x1_min, x1_max))
        plt.ylim((x2_min, x2_max))
        plt.grid(True)
        plt.title(u'sigma = %.2f' % s, fontsize=16)
    plt.tight_layout()
    plt.subplots_adjust(top=0.9)
    plt.show()

 

相關文章