1 划分聚類分析
1.1 K 均值聚類
最常見的划分方法是K均值聚類分析。從概念上講,K均值算法如下:
(1) 選擇K個中心點(隨機選擇K行);
(2) 把每個數據點分配到離它最近的中心點;
(3) 重新計算每類中的點到該類中心點距離的平均值(也就說,得到長度為p的均值向量,這里的p是變量的個數);
(4) 分配每個數據到它最近的中心點;
(5) 重復步驟(3)和步驟(4)直到所有的觀測值不再被分配或是達到最大的迭代次數(R把10次作為默認迭代次數)。
R軟件使用Hartigan & Wong(1979)提出的有效算法,這種算法是把觀測值分成k組並使得觀測值到其指定的聚類中心的平方的總和為最小。
K均值聚類能處理比層次聚類更大的數據集。在R中K均值的函數格式是kmeans(x,centers),這里x表示數值數據集(矩陣或數據框),centers是要提取的聚類數目。函數返回類的成員、類中心、平方和(類內平方和、類間平方和、總平方和)和類大小。
由於K均值聚類在開始要隨機選擇k個中心點,在每次調用函數時可能獲得不同的方案。使用set.seed()函數可以保證結果是可復制的。此外,聚類方法對初始中心值的選擇也很敏感。
kmeans()函數有一個nstart選項嘗試多種初始配置並輸出最好的一個。例如,加上nstart=25會生成25個初始配置。通常推薦使用這種方法。
不像層次聚類方法,K均值聚類要求你事先確定要提取的聚類個數。同樣,NbClust包可以用來作為參考。另外,在K均值聚類中,類中總的平方值對聚類數量的曲線可能是有幫助的。可根據圖中的彎曲選擇適當的類的數量。
圖像可以用下面的代碼產生:
wssplot<-function(data,nc=15,seed=123){
wss<-(nrow(data)-1)*sum(apply(data, 2, var))
for (i in 2:nc){
set.seed(seed)
wss[i]<-sum(kmeans(data,centers = i)$withiness)}
plot(1:nc,wss,type="b",xlab="Number of Clusters",
ylab="within groups sum of squares")}
data參數是用來分析的數值數據,nc是要考慮的最大聚類個數,而seed是一個隨機數種子。
用K均值聚類來處理包含178種意大利葡萄酒中13種化學成分的數據集。該數據最初來自於UCI機器學習庫(http://www.ics.uci.edu/~mlearn/MLRepository.html),但是可以通過rattle
包獲得。在這個數據集里,觀測值代表三種葡萄酒的品種,由第一個變量(類型)表示。
(1)葡萄酒數據的K均值聚類:
data(wine, package="rattle")
head(wine)
df <- scale(wine[-1]) #標准化數據,均值未0,方差為1
wssplot(df)
結果分析:畫出組內的平方和和提取的聚類個數的對比。從一類到三類下降得很快(之后下降得很慢),建議選用聚類個數為二、三的解決方案。
library(NbClust)
set.seed(1234)
devAskNewPage(ask=TRUE)
nc <- NbClust(df, min.nc=2, max.nc=15, method="kmeans")
結果分析:左圖表示從一類到三類變化時,組內的平方總和有一個明顯的下降趨勢。三類之后,下降的速度減弱,暗示着聚成三類可能對數據來說是一個很好的擬合。
table(nc$Best.n[1,]) #查看分組支持數
結果分析:這里,19個評判准則贊同聚類個數為3,2個判定准則贊同聚類個數為2,等等。
barplot(table(nc$Best.n[1,]), #分組支持數可視化
xlab="Number of Clusters", ylab="Number of Criteria",
main="Number of Clusters Chosen by 26 Criteria")
結果分析:使用NbClust包中的26個指標推薦的聚類個數,可以看到聚為3類擁有最多的支持數。
set.seed(1234)
fit.km <- kmeans(df, 3, nstart=25) #進行K均值聚類分析
fit.km$size #查看聚成三類后,每類有多少變量
查看標准化之后數據據的維度,有178行,13列
fit.km$centers #查看聚類的中心
aggregate(wine[-1], by=list(cluster=fit.km$cluster), mean) #使用aggregate()函數和類的成員來得到原始矩陣中每一類的變量均值
交叉列表類型(葡萄酒品種)和類成員由下面的代碼表示:
ct.km <- table(wine$Type, fit.km$cluster)
ct.km
可以用flexclust包中的蘭德指數(Rand index)來量化類型變量和類之間的協議:
library(flexclust)
randIndex(ct.km)
結果分析:調整的蘭德指數為兩種划分提供了一種衡量兩個分區之間的協定,即調整后機會的量度。它的變化范圍是從–1(不同意)到1 (完全同意)。葡萄酒品種類型和類的解決方案之間的協定約等於0.9,結果不壞。
1.2 圍繞中心點的划分
因為K均值聚類方法是基於均值的,所以它對異常值是敏感的。一個更穩健的方法是圍繞中
心點的划分(PAM),K均值聚類一般使用歐幾里得距離,而PAM可以使用任意的距離來計算。
PAM算法如下:
(1) 隨機選擇K個觀測值(每個都稱為中心點);
(2) 計算觀測值到各個中心的距離/相異性;
(3) 把每個觀測值分配到最近的中心點;
(4) 計算每個中心點到每個觀測值的距離的總和(總成本);
(5) 選擇一個該類中不是中心的點,並和中心點互換;
(6) 重新把每個點分配到距它最近的中心點;
(7) 再次計算總成本;
(8) 如果總成本比步驟(4)計算的總成本少,把新的點作為中心點;
(9) 重復步驟(5)~(8)直到中心點不再改變。
可以使用cluster包中的pam()函數使用基於中心點的划分方法。格式如下:
pam(x, k, metric="euclidean", stand=FALSE)
x表示數據矩陣或數據框,k表示聚類的個數,metric表示使用的相似性/相異性的度量,而stand是一個邏輯值,表示是否有變量應該在計算該指標之前被標准化。
(1)對葡萄酒數據使用基於質心的划分方法:
library(cluster)
set.seed(1234)
fit.pam <- pam(wine[-1], k=3, stand=TRUE) #聚類數據的標准化
fit.pam$medoids #輸出中心點
結果分析:這里得到的中心點是葡萄酒數據集中實際的觀測值。
clusplot(fit.pam, main="Bivariate Cluster Plot") #畫出聚類方案
PAM在如下例子中的表現不如K均值:
ct.pam <- table(wine$Type, fit.pam$clustering)
ct.pam
randIndex(ct.pam)
結果分析:flexclust包中的蘭德指數(Rand index)來量化類型變量和類之間的協議,調整的蘭德指數為兩種划分提供了一種衡量兩個分區之間的協定,即調整后機會的量度。它的變化范圍是從–1(不同意)到1 (完全同意)。葡萄酒品種類型和類的解決方案之間的協定約等於0.7,結果沒有很好。