模糊c均值聚類(Fuzzy C-Means Clustering,FCM)是最廣泛使用的模糊聚類算法之一,與k均值劃分聚類較為相似,通過不斷迭代使組內平方和最小化。二者最主要的區別在於,k均值劃分聚類中每個對象只由一個聚類中心約束,模糊c均值聚類中對象與所有聚類中心都有關。
組內平方和計算如下:
其中uijm通過下式計算:
uij是對象xi屬於簇cj的程度,與對象xi離cj質心(聚類中心)的距離成反比;uj是簇j的質心。模糊c均值聚類中,一個對象理論上可以被分配為所有組,並通過給定對象在各組中的成員值(membership value)描述對象屬於某一類的程度(可以理解為概率)。成員值介於0和1之間,接近0代表了對象遠離該聚類中心,接近1代表對象靠近該聚類中心,每個對象在各類中成員值的總和為1。
聚類中心計算為組內所有對象的質心,並根據對象的成員度進行加權。
m是模糊參數,理論上可以取大於或等於1的任何值,當接近於1時聚類結果將與k均值劃分等硬聚類相似,值接近無限將導致完全模糊,通常使用m=2。
模糊c均值聚類過程可以總結如下:
(1)指定聚類數k;
(2)為每個對象任意分配一組初始成員值;
(3)使用上述公式計算每個聚類簇的質心;
(4)使用上述公式重新計算每個對象在各聚類簇中的成員值;
(5)重複(3)、(4)過程,直到成員值收斂(不再變動)或達到最大迭代次數為止。
由於在計算方式上與k均值劃分聚類具有類似點,因此也可能存在相似的問題:聚類結果受初始k的數量影響顯著;不同的初始化配置可能導致不同的結果;如果到達最大迭代次數時仍未收斂,則可能會陷入局部最小值。
接下來展示R語言執行模糊c均值聚類的方法。
示例數據和R代碼的百度盤連結:
https://pan.baidu.com/s/1KjnCaP4Gfdys9lSrw5mUUA
cluster包提供了模糊c均值聚類方法,通過函數fanny()實現。
library(cluster)
#示例數據包含 15 個樣本(對象),20 個變量
dat <- read.delim('data.txt', sep = '\t', row.names = 1, stringsAsFactors = FALSE, check.names = FALSE)
#推薦變量標準化,主要用於消除量綱差異,降低極端值比重
dat <- scale(dat)
#已知這些樣本來自於 3 組數據,但不明確具體哪些樣本是一組的,用來演示模糊 c 均值聚類過程
#模糊 c 均值聚類,詳情 ?fanny
set.seed(123)
cm.fanny <- fanny(dat, k = 3, metric = 'euclidean', maxit = 100)
cm.fanny
#或者也可計算對象間距離,將距離作為模糊 c 均值聚類的輸入,不使用原始數據
dis_euc <- vegan::vegdist(dat, method = 'euclidean')
set.seed(123)
cm.fanny <- fanny(dis_euc, k = 3, diss = TRUE, maxit = 100)
cm.fanny
#查看主要結果
names(cm.fanny)
head(cm.fanny$membership) #對象屬於某一類的程度,即成員值,行和為 1
cm.fanny$clustering #最佳分類,即各對象最接近的聚類簇
#輪廓圖
plot(silhouette(cm.fanny))
輪廓圖顯示對象分類為3組的情況良好。
將模糊c均值聚類和排序圖(如PCoA)結合,觀測對象之間的整體相似性或差異,以及識別的分類特徵。
#以 PCoA 為例降維,並將聚類結果標註在排序圖中
#以上述所得對象間歐幾裡得距離為例,計算 PCoA
pcoa <- cmdscale(dis_euc, k = (nrow(dat) - 1), eig = TRUE)
eig_prop <- 100*pcoa$eig/sum(pcoa$eig)
pcoa_site <- pcoa$point[ ,1:2]
plot(pcoa_site,
xlab = paste('PCoA axis1:', round(eig_prop[1], 2), '%'),
ylab = paste('PCoA axis2:', round(eig_prop[2], 2), '%'))
#標註各對象最接近的聚類簇
for (i in 1:3) {
gg <- pcoa_site[cm.fanny$clustering == i, ]
hpts <- chull(gg)
hpts <- c(hpts, hpts[1])
lines(gg[hpts, ], col = 1+1)
}
#星圖展示了各對象的成員值
stars(cm.fanny$membership, location = pcoa_site, draw.segments = TRUE,
add = TRUE, scale = FALSE, col.segments = 2:4, len = 0.5)
星圖展示了對象屬於各聚類簇的成員值,面積越大代表成員值越高,並將各對象所屬的最佳聚類簇用紅線連接。數據集整體特徵一目了然。
相比上述plot()作圖,factoextra包提供了更便捷的方法,以下是一些參考。
#factoextra 包的可視化方案
library(factoextra)
#聚類和 PCA 結合,點的顏色和形狀代表分組,分組橢圓展示為 95% 置信區間
fviz_cluster(cm.fanny, ellipse.type = 'norm', repel = TRUE, palette = 'jco',
ellipse.level = 0.95, ggtheme = theme_minimal(), legend = 'right')
#輪廓圖
fviz_silhouette(cm.fanny, palette = 'jco', ggtheme = theme_minimal())
e1071包也是可用於模糊c均值聚類的常用R包,繼續使用上文的示例展示e1071包中的方法。
做過表達譜時間趨勢分析的同學們可能用過一個R包,Mfuzz,它就是以e1071包中的模糊c均值方法為基礎進行時間表達模式聚類的。
library(e1071)
#讀取數據
dat <- read.delim('data.txt', sep = '\t', row.names = 1, stringsAsFactors = FALSE, check.names = FALSE)
#推薦標準化,主要用於消除量綱差異,降低極端值比重
dat <- scale(dat)
#模糊 c 均值聚類,詳情 ?cmeans
#期望分為 3 類,最大迭代 100 次
set.seed(123)
cm.cmeans <- cmeans(dat, centers = 3, iter.max = 100, dist = 'euclidean', method = 'cmeans')
cm.cmeans
#查看主要結果
summary(cm.cmeans)
head(cm.cmeans$membership) #對象屬於某一類的程度,即成員值,行和為 1
cm.cmeans$cluster #最佳分類,即各對象最接近的聚類簇
可以結合一些其它包的可視化方法,觀測對象分類詳情。
#使用 corrplot 包描述對象歸屬的成員值
library(corrplot)
corrplot(cm.cmeans$membership, is.corr = FALSE)
該圖代表了模糊c均值聚類計算的各對象在各類別中的歸屬程度,明確屬於某一聚類簇的對象在該簇中具有較高的成員值。
同樣地,再結合排序圖觀測各類別的邊界,將聚類結果標註在圖中。
#factoextra 包的可視化方案,和 PCA 結合
#點的顏色和形狀代表分組,分組橢圓展示為 95% 置信區間
library(factoextra)
fviz_cluster(list(data = dat, cluster = cm.cmeans$cluster), palette = 'jco',
ellipse.type = 'norm', ellipse.level = 0.95, ggtheme = theme_minimal())
不同顏色和形狀的點代表對象屬於不同的類別,各組中心最大的點代表了聚類中心,顯示該示例數據的樣本分類還是很好的。
https://www.datanovia.com/en/lessons/fuzzy-clustering-essentials/fuzzy-c-means-clustering-algorithm/https://www.datanovia.com/en/lessons/fuzzy-clustering-essentials/cmeans-r-function-compute-fuzzy-clustering/Bezdek J C. 1981. Pattern Recognition with Fuzzy Objective Function Algorithms. New York: Plenum Press.