R語言從入門到精通:Day15(聚類分析)
- 2019 年 11 月 23 日
- 筆記
聚類分析是一種數據歸約技術,旨在揭露一個數據集中觀測值的子集。它可以把大量的觀測值歸約為若干個類。
這裡的類被定義為若干個觀測值組成的群組,群組內觀測值的相似度比群間相似度高。這不是一個精確的定義,從而導致了各種聚類方法的出現。最常用的兩種聚類方法是層次聚類(hierarchical agglomerative clustering)和劃分聚類(partitioning clustering)。
在層次聚類中,每一個觀測值自成一類,這些類每次兩兩合併,直到所有的類被聚成一類為止。在劃分聚類中,首先指定類的個數K,然後觀測值被隨機分成K類,再重新形成聚合的類。對於劃分聚類來說,最常用的演算法是K均值(K-means)等。
在開始討論這兩類聚類方法之前,我們先要熟悉一下聚類方法都需要遵循的步驟。
**需提前按照的R包:cluster、NbClust、flexclust、fMultivar、ggplot2和rattle。
一個全面的聚類分析一般會包括以下11個典型步驟:
1.選擇合適的變數;
2.縮放數據(最常用的方法是將每個變數標準化為均值=0和標準差=1的變數。其他的替代方法包括每個變數被其最大值相除或該變數減去它的平均值併除以變數的平均絕對偏差);
3.尋找異常點;
4.計算距離;
5.選擇聚類演算法;
6.獲得聚類方法;
7.確定類的數目(NbClust包的函數NbClust()可以解決這個問題);
8.獲得最終的聚類解決方案;
9.結果可視化;
10.解讀類;
11.驗證結果(包fpc、包clv和包clValid包含了評估聚類解的穩定性的函數)。
層次聚類
首先,對於層次聚類而言,起初每一個實例或觀測值屬於一類。每一次把兩類聚成新的一類,直到所有的類聚成單個類為止,演算法如下:
(1) 定義每個觀測值(行或單元)為一類;
(2) 計算每類和其他各類的距離;
(3) 把距離最短的兩類合併成一類,這樣類的個數就減少一個;
(4) 重複步驟(2)和步驟(3),直到包含所有觀測值的類合併成單個的類為止。
不同的層次聚類方法主要區別在於步驟(2),即計算類之間的距離的方法不同。常見的層次聚類方法見表1。
表1,五種常見的層次聚類方法。
層次聚類方法可以用函數hclust()來實現,格式是hclust(d, method=),其中參數d是通過 dist()函數產生的距離矩陣,並且參數method包括 "single"、"complete"、"average"、 "centroid"和"ward"(和表格裡面的5種一一對應)。層次聚類的測試數據集主要來自於包flexclust中的數據集nutrient。
採用平均聯動的聚類結果如圖1。
圖1:平均聯動聚類結果
樹狀圖應該從下往上讀,它展示了這些條目如何被結合成類。每個觀測值起初自成一類,然後相距最近的兩類合併。合併繼續進行下去,直到所有的觀測值合併成一類。高度刻度代表了該高度類之間合併的判定值。但是這幅圖並不能指出聚類的適當個數。包NbClust提供了眾多的指數來確定在一個聚類分析里類的最佳數目。四個評判準則贊同聚類個數為2,四個判定準則贊同聚類個數為3,結果如圖2。
圖2:理想的聚類個數
我們嘗試聚類個數為5(四個判定準則贊同,如圖2)的情形。
圖3:聚類個數為5
層次聚類
當需要嵌套聚類和有意義的層次結構時,層次聚類特別有用。在某種意義上分層演算法是嚴苛的,一旦一個觀測值被分配給一個類,它就不能在後面的過程中被重新分配。另外,層次聚類難以應用到有數百甚至數千觀測值的大樣本中。我們這裡將討論兩種方法:K-means和基於中心點的劃分(PAM)。
K-means
從概念上講,K-means演算法如下:
(1) 選擇K個中心點(隨機選擇K行);
(2) 把每個數據點分配到離它最近的中心點;
(3) 重新計算每類中的點到該類中心點距離的平均值(也就說,得到長度為p的均值向量,這裡的p是變數的個數);
(4) 分配每個數據到它最近的中心點;
(5) 重複步驟(3)和步驟(4)直到所有的觀測值不再被分配或是達到最大的迭代次數(R把10次作為默認迭代次數)。
在R中K-means的函數格式是kmeans(x, centers),這裡參數x表示數值數據集(矩陣或數據框),參數centers是要提取的聚類數目。
由於K均值聚類在開始要隨機選擇k個中心點,在每次調用函數時可能獲得不同的方案。使用函數set.seed()可以保證結果是可複製的。此外,聚類方法對初始中心值的選擇也很敏感。函數kmeans()有一個參數nstart嘗試多種初始配置並輸出最好的一個。例如,加上nstart=25 會生成25個初始配置。通常推薦使用這種方法。
不像層次聚類方法,K均值聚類要求你事先確定要提取的聚類個數。同樣,包NbClust可以用來作為參考,同時我們也提供了一個自定義的函數wssplot來幫助你確定類的個數。
(劃分聚類的測試數據集來自於包rattle的數據集wine,為了驗證分類結果的準確性,我們選擇先放棄第一個變數[類型],進行聚類分析,再將結果和第一個變數對比,看看能否恢復已知的類型)
圖4:函數wssplot的結果
圖4表明從一類到三類下降得很快(之後下降得很慢),建議選用聚類個數為三的解決方案。
圖5:包NbClust的結果
圖5也推薦聚為三類。
利用包flexclust中的函數randIndex()可以衡量兩個分類之間的差異,結果為0.897。說明我們聚為3類的選擇是很準確的。(程式碼聯繫文末客服,識別二維碼領取)
基於中心點的劃分
因為K-means聚類方法是基於均值的,所以它對異常值是敏感的。一個更穩健的方法是圍繞中心點的劃分(PAM)。與其用質心表示類,不如用一個最有代表性的觀測值來表示(稱為中心點)。K-means聚類一般使用歐幾里得距離,而PAM可以使用任意的距離來計算。因此,PAM可以容納混合數據類型,並且不僅限於連續變數(PAM演算法和k-means聚類很類似,就不贅述了)。
包cluster中的函數pam()使用基於中心點的劃分方法。格式是pam(x, k, metric="euclidean", stand=FALSE),這裡的參數x表示數據矩陣或數據框,參數k表示聚類的個數, 參數metric表示使用的相似性/相異性的度量,而參數stand是一個邏輯值,表示是否有變數應該在計算該指標之前被標準化(這裡測試數據集和k-means聚類方法一樣)。
圖6:PAM聚類方法的結果
但是,PAM在本例中的表現不如K均值,函數randIndex()結果下降為了0.699。
到這裡,常見的兩種聚類方法已經討論完畢,但是聚類分析是一種旨在識別數據集子組的方法,並且 在此方面十分擅長。事實上,它甚至能發現不存在的類。這裡,程式碼中提供一個對完全隨機數據進行PAM聚類的例子。圖7展示了這個數據集的分布情況。其中並不存在聚類。但是函數wssplot()和包NbClust的結果都建議分類為2或3。利用PAM方法進行雙聚類結果如圖8。
圖7:完全隨機數據的分布
圖8:PAM雙聚類結果
很明顯劃分是人為的。實際上在這裡沒有真實的類。NbClust包中的立方聚類規則(Cubic Cluster Criteria,CCC)往往可以幫助我們揭示不存在的結構。當CCC的值為負並且對於兩類或是更多的類遞減時,就是典型的單峰分布(如圖9)。
圖9:CCC規則的示意圖
當然,你也可以嘗試多種聚類方法,如果結果都很類似,就可以確信你的聚類結果是準確的了。綜合來說,聚類分析是一個寬泛的話題,而R有一些最全面的方案來實施現有的方法。想要了解更多,可以CRAN的聚類分析和有限混合模型部分,見如下鏈接。https://cran.r-project.org/web/views/Cluster.html