注,有疑問 加QQ群..[174225475].. 共同探討進步
有償求助請 出門左轉 door , 合作愉快
1. 相關概念科普
度矩陣
度矩陣為對角矩陣,對角線上的值表示 與該點 有來往的 其他點的個數 即度 為 與節點 相連的 個數
鄰接矩陣
鄰接矩陣 表示圖上 各點之間 是否有聯系或者聯系程度, 可以是 1/0 也可以是 具體權值
拉普拉斯矩陣
圖論中的的 拉普拉斯矩陣(也被稱為導納矩陣/吉爾霍夫矩陣/離散拉普拉斯)是圖的矩陣表示. 它是 度矩陣 和 鄰接矩陣 的差. 拉普拉斯矩陣 結合 吉爾霍夫理論 可以用來計算圖的最小生成樹的個數。
拉普拉斯矩陣還可用來尋找圖的其他屬性: 譜圖理論(spectral graph theory)
黎曼幾何的Cheeger不等式有涉及了拉普拉斯矩陣的離散模擬. 這或許是譜圖理論中最重要的定理也是在算法應用中最有用的facts.它通過拉普拉斯矩陣的第二特征值來近似圖的最小割
譜的定義 就是:
方陣作為線性算子,它的所有特征值的全體 統稱方陣的譜;
方陣的譜半徑為最大的特征值;
矩陣A的譜半徑:()的最大特征值。
其實,這里譜的本質是偽逆,是中奇異值的平方
2. 譜聚類的基本思想
2.1 聚類與圖論
所謂聚類(Clustering), 就是要把一堆樣本合理地分成兩份或者份. 從圖論的角度來說,聚類的問題就相當于一個圖的分割問題. 即給定一個圖
, 頂點集
表示各個樣本,帶權的邊表示各個樣本之間的相似度,譜聚類的目的便是要找到一種合理的分割圖的方法,使得分割后形成若干個 子圖,連接不同 子圖 的邊的權重(相似度)盡可能低,同 子圖內 的邊的權重(相似度)盡可能高.被割掉各邊的權值和越小代表被它們連接的子圖之間的相似度越小,隔得越遠. 物以類聚,人以群分,相似的在一塊兒,不相似的彼此遠離
至于如何把圖的頂點集分割/切割為不相交的子圖有多種辦法,如
- cut/Ratio Cut
- Normalized Cut
- 不基于圖,而是轉換成SVD能解的問題
2.2 最小割
在將數據從點集的結構轉換為了圖的結構后,我們可以引入更多圖論中的概念來幫助理解聚類的本質. 比如說最小割的概念(Minimum cut)
最小割是指去掉圖中的一些帶權邊,在使得圖從聯通圖變為不聯通圖的前提下,盡可能的讓去掉的邊權值之和盡可能小。對于數據的相似性圖來說,最小割就是要去除一些很弱的相似性,把數據點從一個互相連接的整體分為兩個或者多個獨立的部分,這其實就是一個聚類的過程。去除的權值就是聚類后不同組別間的相似程度,我們希望這個值盡可能的小,也就是希望不同組別之間的差距盡可能的大
不過,僅僅是用最小割來聚類存在著一些缺陷,因為我們只考慮了不同類的點之間相似度要小,而一個好的聚類還要具有同一類點相似度大的特征。比如下圖就是一個例子,一個好的聚類應該是在綠線處分割整個圖,但使用最小割卻會割在紅色的位置
如下圖所示,每個頂點是一個樣本,共有7個樣本(實際中一個樣本是特征向量). 邊的權值就是樣本之間的相似度. 然后我們需要分割,分割之后要使得連接不同組之間的邊的權重盡可能低(組間相似度小),組內部的邊的權重盡可能高(組內相似度高)
比如我們把中間的邊去掉,就滿足上面的簇間相似性最小,簇內相似性最大。如下圖
3. 算法步驟
譜聚類算法主要有下面幾部分:
3.1 未正則拉普拉斯矩陣 的譜聚類算法
3.1.1 計算得到圖的鄰接矩陣
,以及拉普拉斯矩陣
;
給定樣本的原始特征,我們需要計算兩兩樣本之間的相似度值,才能構造出鄰接矩陣 . 我們一般使用高斯核函數來計算相似度。公式如下:
即
如果樣本是對應數據集
的第
行,則上述公式中的
高斯核相似度公式用 R 來表達:
S(dt) = exp(-(dist(dt)^2)/(2*sigma^2))
其中 和
是兩個樣本(行向量),
是樣本
對應的第
個原始特征向量,我們可以計算出它們二者之間的相關性(高斯核). 注意,鄰接矩陣的對角線元素一致等于零. 這樣我們就得到了鄰接矩陣
拉普拉斯矩陣 , 其中
為上面圖的度矩陣,度是圖論中的概念,也就是矩陣E行或列的元素之和。后面我們就要基于矩陣
來進行研究
3.1.2 聚類劃分準則
關于劃分準則的問題是聚類技術中的核心。譜聚類被看作屬于圖論領域的問題,那個其劃分也會和邊的權重有關
準則1:最小化進行分割時去掉的邊的權重之和
這個準則直觀地讓分割之后簇之間的相似度最小了。但是有個問題,就是這個準則沒有考慮到簇的大小,容易造成一個樣本就能分為一個簇。為了避免這個問題,有了下面的準則
準則2:考慮簇的大小
準則2相比于準則1的改進,類似于中的增益比率和
的信息增益的改進。在
中,如果某一組包含的頂點數越少,那么它的值就越大。在一個最小化問題中,這相當于是懲罰,也就是不鼓勵將組分得太小。現在只要將最小化
解出來,分割就完成了。不幸的是,這是個
難問題。想要在多項式時間內解出來,就要對這個問題作一個轉化了。在轉化的過程中,就用到上面提到的L的那一組性質,經過若干推導,最后可以得到這樣的一個問題
但到了這關鍵的最后一步,咱們卻遇到了一個比較棘手的問題,即由之前得到的拉普拉斯矩陣的性質最小特征值為
,對應的特征值為
.其不滿足
與
正交的條件,那該怎么辦呢?根據論文“A Tutorial on Spectral Clustering”中所說的Rayleigh-Ritz 理論,我們可以取第
小的特征值,以及對應的特征向量
更進一步,由于實際中,特征向量里的元素是連續的任意實數,所以可以根據
是大于0,還是小于0對應到離散情況下的
,決定
是取
還是取
.而如果能取
的前
個特征向量,進行
聚類,得到
個簇,便從二聚類擴展到了
聚類的問題 (
表示A的補集)
而所要求的這前個特征向量就是拉普拉斯矩陣的特征向量(計算拉普拉斯矩陣的特征值,特征值按照從小到大順序排序,特征值對應的特征向量也按照特征值遞增的順序排列,取前
個特征向量,便是我們所要求的前
個特征向量)!
所以,問題就轉換成了:求拉普拉斯矩陣的前個特征值,再對前
個特征值對應的特征向量進行
聚類。而兩類的問題也很容易推廣到
類的問題,即求特征值并取前
個最小的,將對應的特征向量排列起來,再進行
聚類. 兩類分類和多類分類的問題,如出一轍
巧妙地把一個NP難度的問題轉換成拉普拉斯矩陣特征值(向量)的問題,將離散的聚類問題松弛為連續的特征向量,最小的系列特征向量對應著圖最優的系列劃分方法。剩下的僅是將松弛化的問題再離散化,即將特征向量再劃分開,便可以得到相應的類別。不能不說妙哉!
3.1.3 求出
的前
個特征值及對應的特征向量
在本文中,除非特殊說明,否則“前個”指按照特征值的大小從小到大的順序)以及對應的特征向量
PS: 是計算前
小的特征向量,如果是
則是計算前
大
3.1.4 根據新生成的特征矩陣進行
聚類
把這個特征(列)向量排列在一起組成一個
的矩陣,將其中每一行看作
維空間中的一個向量,并使用
算法進行聚類. 聚類的結果中每一行所屬的類別就是原來 Graph 中的節點亦即最初的
個數據點分別所屬的類別
3.1.5 總結一下完整的譜聚類算法的流程
- 確認輸入參數:一個描述數據相似性圖的鄰接矩陣
,和聚類的目標類數目
- 計算度矩陣
和 拉普拉斯矩陣
- 計算特征值方程
的前
個特征向量,記為
- 通過
按列排成矩陣
-
的第
行的行向量記為
- 對
進行
聚類
- 將
的類別分配給
, 即
- 輸出聚類結果
整個過程都只用到了包括求解特征值等基本線性代數運算,因此譜聚類是一種推導有些繁雜,但是實現很簡單的聚類算法
3.2 正則的拉普拉斯矩陣 的譜聚類算法
3.2.1 對稱拉普拉斯矩陣的譜聚類算法
- 將 為正則拉普拉斯中的
替換成
- 同時在完成
維特征向量提取之后,進行
聚類之前,添加一步:
將維 特征向量對應的 各樣本 進行單位化使得
即
mx2 <- mx1/sqrt(rowSums(mx1^2))
- 然后在此基礎上繼續
聚類
下面是在參加某賽事時正則化譜聚類實現步驟
library(data.table)
library(dplyr)
library(ggplot2)
library(geosphere)
setwd('xxx/spec')
train1 <- fread('train.csv',header = FALSE,encoding = 'UTF-8')
test1 <- fread('test.csv',header = FALSE,encoding = 'UTF-8')
dt_all <- rbind(train1,test1)
dist2 = distm(dt_all[,c('longitude','latitude')])/1000
lamb1 <- sqrt(ncol(dt_all[,c('longitude','latitude')]))/sqrt(2)
W1 <- exp(-dist2^2/(2*lamb1^2))
rm(dist2)
W1[W1<1e-15]=0
W2 <- as(W1,'sparseMatrix')
diag1 <- rowSums(W1)
rm(W1)
D1 <- Matrix::sparseMatrix(i=seq(1,length(diag1)),
j=seq(1,length(diag1)),
x=diag1) # 度矩陣
D2 <- Matrix::sparseMatrix(i=seq(1,length(diag1)),
j=seq(1,length(diag1)),
x=diag1^(-1/2))
D3 <- Matrix::sparseMatrix(i=seq(1,length(diag1)),
j=seq(1,length(diag1)),
x=diag1^(1/2))
L1 <- D1-W2
L2 <- D2%*%L1%*%D3 #拉普拉斯矩陣
rm(L1,D1,D2,D3)
eig1 <- eigen(L2)
mx1 <- eig1$vectors[,-c(1:(ncol(eig1$vectors)-k))]
mx2 <- mx2/sqrt(rowSums(mx1^2))
# find best k value for kmeans
library(factoextra)
fviz_nbclust(area1, kmeans, method = "silhouette",k.max = 50)
# the larger the better for result value(this formu is friendly for bigdata)
kmean1 <- kmean(mx2,49)
# plot
ggplot()+
geom_point(data=dt_all,aes(x=longitude,y=latitude,color=as.factor(kmean1$cluster)))+
geom_text(data=NULL,aes(x=kmean1$centers[,1],
y=kmean1$centers[,2],
label=row.names(kmean1$centers)))+
theme(legend.position = 'none')
由于樣本huge,eigen時cost too much, so kmeans替代,以上代碼作為R實現步驟留念,指不定哪天R真正解決了分布式問題,譜聚類就能跟kmeans一樣高效了
Kernlab包中有specc函數可實現此功能,但礙于樣本量巨大,2個小時沒出結果也只能作罷
3.2.2 隨機游走拉普拉斯矩陣 的譜聚類算法
它的變化就是將 矩陣的
計算方式改為
,其他步驟與 未正則拉普拉斯矩陣 的譜聚類算法相同