1. 程式人生 > >機器學習筆記(九)聚類演算法及實踐(K-Means,DBSCAN,DPEAK,Spectral_Clustering)

機器學習筆記(九)聚類演算法及實踐(K-Means,DBSCAN,DPEAK,Spectral_Clustering)

這一週學校的事情比較多所以拖了幾天,這回我們來講一講聚類演算法哈。

首先,我們知道,主要的機器學習方法分為監督學習和無監督學習。監督學習主要是指我們已經給出了資料和分類,基於這些我們訓練我們的分類器以期達到比較好的分類效果,比如我們前面講的Logistic迴歸啊,決策樹啊,SVM啊都是監督學習模型。無監督學習就是指我們就只有資料,沒有分類結果,然後根據資料進行建模能夠給出哪些樣本是屬於一類的一個過程,通常我們就稱之為聚類。

今天我主要介紹以下幾種最常見的聚類演算法,包括K-Means演算法,基於密度的聚類(DBSCAN)演算法,密度最大值演算法(DPEAK),譜聚類演算法,基本上也是從易到難,從原理講講我自己的理解,希望對大家有用。

====================================================================

K-Means演算法。

原理上來講,K-Means演算法其實是假設我們資料的分佈是K個sigma相同的高斯分佈的,每個分佈裡有N1,N2……Nk個樣本,其均值分別是Mu1,Mu2……Muk,那麼這樣的話每個樣本屬於自己對應那個簇的似然概率就是


這個套路我們就很熟悉了,下面就是取對數似然概率,要求似然概率的最大值,給它加個負號就可以作為損失函數了,考慮到所有簇的sigma是相等的,所以我們就可到了K-Means的損失函式


接著我們對損失函式求導數為0,就可以得到更新後最佳的簇中心了


這樣我們就得到了所謂的K-Means演算法

1 初始選擇K個類別中心。

2 將每個樣本標記為距離類別中心最近的那個類別。

3 將每個類別中心更新為隸屬該類別所有點的中心。

4 重複2,3兩步若干次直至終止條件(迭代步數,簇中心變化率,MSE等等)

現在我們回過頭來看看K-Means演算法的問題。

首先,正如我剛開始介紹它的時候,它是假設資料服從sigma相同的混合高斯分佈的,所以最後分類的結果肯定是若干個類圓形的區域,這就很大程度上限制了它的應用範圍,如果我們的資料是那種比較奇葩的形狀,比如什麼扇形啊,圓環啊,你會發現K-Means的效果其實不是很叫人滿意。

其次,你得給出這個分類的數目K啊,有一定的先驗條件還好,如果是兩眼一抹黑,怎麼確定呢?猜唄,或者試唄,用一定的評價標準選擇最佳那個就成。還有就是初始簇中心的選擇,K-Means的結果對初值是敏感的,比如說樣本分為三個簇,你一開始把兩個中心定在某一個簇中,還有一箇中心處在另外兩個簇的中間,這樣最後的結果很可能是那兩個簇被劃分成一類,還有一個簇被強行劃分成兩個簇這樣。所以為了解決這個初值敏感問題,又提出了K-Means++演算法,它的做法就是你先隨機指定第一個簇中心,然後計算所有點到該簇中心的距離,以這個距離作為權值來選擇下一個簇中心,一定程度上可以解決簇中心初值選擇不合理的問題。

最後還有一個問題,就類似於上一篇我們講的SVM一樣,如果我們採用線性可分SVM方法,一個異常點就可以把我們的分割超平面帶跑偏導致泛化能力被削弱。K-Means中我們採用均值來更新簇中心,同樣的,一個異常點會導致新的這個簇中心發生比較大的偏離,而且再更新的時候我們還是要考慮那個異常點,所以就不會得到比較好的效果。

說了這麼多K-Means的缺點都顯得它一無是處了,我們還是要說K-Means作為一種最經典的聚類演算法,它簡單,快速,在應對大資料的時候相對優勢會比較大,有的時候還可以作為其他聚類演算法中的一步。

====================================================================

DBSCAN演算法。

前面講了K-Means演算法主要針對那種類圓形區域資料的聚類,相對來說應用範圍窄了一點。而密度聚類可以彌補這個缺點,可用於任何形狀的聚類。這個演算法需要我們調節兩個引數,半徑sigma,最小數目m,先介紹該演算法的一些概念

核心物件:對於一個物件它的sigma領域內至少有m個物件,那我們就稱之為核心物件

直接密度可達:如果一個物件處在一個核心物件的sigma領域內,那稱這兩個物件直接密度可達

密度可達(相連):如果一個物件a和b直接密度可達,物件b和c也是直接密度可達,那麼我們稱a和c是密度可達的,也稱這兩個物件是密度相連的。

DBSCAN的演算法就是我們先找到一個核心物件,從它出發,確定若干個直接密度可達的物件,再從這若干個物件出發,尋找它們直接密度可達的點,直至最後沒有可新增的物件了,那麼一個簇的更新就完成了。我們也可以說,簇其實就是所有密度可達的點的集合。

它的優勢在哪兒呢?

首先,它對這個簇的形狀沒要求,只要這些點密度可達我們就把它歸為一個簇,這樣不管你的形狀多奇葩,最後我們都能把它分到同一個簇當中。

其次,我們可以想一下那些異常點,它偏離正常物件很多,所以它既不是核心物件,然後對其它的點又不是密度可達的,所以最後就被剩了出來沒被分類。因此DBSCAN演算法還有一定的剔除異常值的功能,當然裡,這裡也要注意,如果我們的sigma值太大或者m太小,還是會導致一些異常值渾水摸魚混進某些簇裡或者自成一類等等,總而言之,還是要根據分類的結果進行調參,尋找最佳的分類方式。

====================================================================

DPEAK演算法

密度最大值演算法可以看成是基於以上兩種演算法的一種拓展吧,它的主要優勢在於確定簇中心和排除異常值。

具體的做法怎麼做呢,我們首先給定一個半徑範圍r,然後對我們所有的樣本,計算它的r鄰域內的樣本數目記作它的區域性密度記作rho,第二步,計算每個樣本到密度比它高的點的距離的最小值記作sigma,有了這兩個引數就可以進行我們下一步的篩選工作了,具體分成以下四種情況:

1 rho很小,sigma很大。這個樣本週圍的樣本量很小,但是到比它密度大的點的距離還挺遠的,這說明啥,它是個遠離正常樣本的異常值啊,在偏僻的小角落裡搞自己的小動作啊,果斷踢了它呀。

2 rho很大,sigma也很大。這個樣本週圍樣本量很大,並且要找到比它密度還大的點要好遠好遠,這說明這個點是被眾星環繞的啊,它就是這個簇的王,我們往往把它確定為簇中心。

3 rho很小,sigma也很小。樣本週圍的樣本量很小,但要找到樣本密度比它大的點沒多遠就有,說明這個點是一個處在邊緣上的點,往往是一個簇的邊界。

4 rho很大,sigma很小。該樣本週圍的樣本量很大,但是密度比它還大的居然也不遠,這種情況只會發生在你處在了簇中心的旁邊時,很可惜,也許你是這個簇的核心成員,但你做不了這個簇的王。

好的,基於每個樣本的rho和sigma,我們大概就能確定它們各自的所扮演的角色了,我們把大反派異常值從樣本中剔除,然後把我們找到的rho和sigma都很大的點作為簇中心,再利用K-Means或者DBSCAN演算法進行聚類就能得到相對比較好的結果。

====================================================================

譜聚類

這是要說的最後一種聚類演算法了,我發現今天講聚類公式確實不多,但是打字也好累啊!!!

譜聚類是一種基於圖論的一種聚類方法,我希望通過一種比較直觀的方式給大家解釋清楚它到底在幹什麼。

首先引入幾個概念,譜聚類肯定要講什麼是譜,還有就是相似度矩陣,度矩陣和拉普拉斯矩陣。

譜:方陣的特徵值(不是方陣的話就是左乘其轉置所得方陣的特徵值)稱之為譜,其中最大值稱為譜半徑。

相似度矩陣W:n個樣本則建立一個n*n的矩陣,矩陣第i行第j列的值為第i個樣本和第j個樣本的某種相似度。

度矩陣D:一個n*n的對角陣,第i行第i列的值為相似度矩陣中第i行的所有值之和。

拉普拉斯矩陣L:度矩陣減去相似度矩陣即為拉普拉斯矩陣。

好了,基於以上這些概念,我們來考慮這樣一種情況。對於這樣m個樣本,它們是屬於同一類的,那麼它們是不是可以建立一個m*m的相似度矩陣W,該矩陣還是個對稱陣,緊接著可以求得它的度矩陣和拉普拉斯矩陣,巧就巧在這個矩陣是個半正定的,證明如下


所以拉普拉斯矩陣的特徵值大於等於0。從度矩陣的定義我們知道,它的對角元素等於相似度矩陣每一行的和,因此拉普拉斯矩陣乘以一個全1的向量得到全為0的一個列向量,因此拉普拉斯矩陣存在一個0的特徵值,對應特徵向量為全1向量,也就是說


同樣的假如有另外一個類的n個樣本,同樣的,對於它而言,有


假設這兩個類的樣本毫無相似度,那麼它們兩個樣本混合在一起的相似度矩陣可以表示為


我們已經知道Lm和Ln對應於特徵值0的特徵向量了,那麼可以求得L對於m的兩個特徵向量


那麼我們可以明顯的看到,對應於L最小特徵值0的兩個特徵向量可以明顯的把兩個種類分開,所以推廣開來我們就知道,通過拉普拉斯矩陣最小的K個特徵值對應的特徵向量進行聚類,我們就能確定對應的樣本所屬的類別。當然現實情況中不可能像我們推導的這麼美麗,全1全0的情況很少出現,因為樣本之間多多少少有些藕斷絲連的關係,但據此對特徵向量進行聚類就已經能確定樣本所屬的種類,這就是我們所說的譜聚類。

最後重複一下譜聚類的演算法過程

1 計算相似度矩陣,度矩陣及拉普拉斯矩陣。

2 計算拉普拉斯矩陣前K小的特徵值對應的特徵向量。

3 將這K個特徵向量組成一個新的矩陣,對其行向量進行聚類。

4 行向量的聚類結果代表了原始樣本的聚類結果。

====================================================================

好了,這大概就是我今天想講的演算法的所有內容了,下面就是喜聞樂見的調包環節了,前面被用爛的鳶尾花資料今天終於派不上用場了,所以第一步我們先造一點資料看看

import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
#造資料
N=500
centers=4
data,y=ds.make_blobs(N,centers=centers,random_state=0)
#原始資料分佈
matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
cm = matplotlib.colors.ListedColormap(list('rgbm'))
plt.scatter(data[:,0],data[:,1],c=y,cmap=cm)
plt.title(u'原始資料分佈')
plt.grid()
plt.show()

結果如下


OK,我們先用K-Means試試


#K-Means
from sklearn.cluster import KMeans
model=KMeans(n_clusters=4,init='k-means++')
y_pre=model.fit_predict(data)
plt.scatter(data[:,0],data[:,1],c=y_pre,cmap=cm)
plt.title(u'K-Means聚類')
plt.grid()
plt.show()

結果是


分類結果相當之好啊,除了區域性靠的比較近的幾個點小有錯誤,整體還是叫人滿意的。但不知道少年你是否還記得我之前說的,K-Means有個先驗條件,它是假設資料滿足方差相同的高斯分佈的,所以我們故意使這些資料的方差不同來看看聚類效果是否會大受影響

#方差不等資料
data2,y2=ds.make_blobs(N,centers=centers,cluster_std=(2,2,5,8),random_state=0)
plt.scatter(data2[:,0],data2[:,1],c=y2,cmap=cm)
plt.title(u'原始資料分佈')
plt.grid()
plt.show()
model2=KMeans(n_clusters=4,init='k-means++')
y_pre2=model2.fit_predict(data2)
plt.scatter(data2[:,0],data2[:,1],c=y_pre2,cmap=cm)
plt.title(u'K-Means聚類')
plt.grid()
plt.show()

結果如下




果然,聚類後的資料是一坨一坨那種,並不能把原始資料中間那兩類分開,所以這也驗證了我們之前講的K-Means還是有其侷限性的。

好啦,今天打了好多字呀……祝大家週末愉快,have a nice day~