k-means聚類算法的R語言實現
K-means算法假設要把樣本集分為c個類別,算法描述如下:(1)隨機選擇c個類的初始中心;
(2)在第n次迭代中,對任意一個樣本,求其到每一個中心的距離,將該樣本歸到距離最近的中心所在的類;
(3)更新該類的中心值,一般利用均值、中位點等方法;
(4)對於所有的c個聚類中心,利用(2)( 3 )的迭代法更新后,如果中心點的值不再變化,則迭代結束,否則繼續迭代,當達到最大迭代次數時,中心點仍未收斂的,取最后的中心點為中心。
kmeans 函數幾個參數的具體作用:centers 設置聚類數;iter.max 設置最大迭代次數;nstart 隨機設置初始中心點的次數,也可以理解為重復做kmeans的次數,眾所周知,kmeans對初始中心非常敏感,nstart為10表示做10次kmeans,每次初始中心點隨機生成一次,也可以理解為確定初始中心點時重復 kmeans的次數,每次迭代完成后返回最優解,當nstart 等於1時,等於只做了一次 kmeans,由於初始中心點不同,所以每次結果都不一樣(可以設置隨機種子克服),nstart一般設置在20~25之間,基本保證能返回最優解,每次的聚類結果也大體相同,除非你的數據量很大。
#步驟1 數據集准備及描述
n=100 g=6 set.seed(g) d<-data.frame(x=unlist(lapply(1:g,function(i) rnorm(n/g,runif(1)*i^2))), y=unlist(lapply(1:g,function(i) rnorm(n/g,runif(1)*i^2)))) #生成數據集 解釋:#unlist 給定一個列表結構 x,unlist 將其簡化為生成一個包含 x 中出現的所有原子分量的向量。 # lapply返回一個與 X 長度相同的列表,其中每個元素都是將 FUN 應用於 X 的相應元素的結果。 #runif()函數用於生成從0到1區間范圍內的服從正態分布的隨機數,每次生成的值都不一樣。runif(20) 表示生成20個0到1之間的隨機數 #rnorm(n/g,runif(1)*i^2) 表示總共生成n/g個隨機數,且每個隨機數的大小為runif(1)*i^2 #lapply(1:g,function(i) rnorm(n/g,runif(1)*i^2)) 表示總共生成與(1:g)*(n/g)長度相同的列表,且列表中的數字為runif(1)*i^2,其中i的取值為1:g。 #x=unlist(lapply(1:g,function(i) rnorm(n/g,runif(1)*i^2))) 標識把列表簡化為向量 dim(d)
class(d)
#步驟2 計算簇類數k值
library(cluster) library(fpc) pamk.best<-pamk(d) #判斷是否存在多個聚類
par(mfrow=c(1,2)) #設置畫布展示,1行2張圖 cat("number of clusters estimated by optimum average silhouette width:",pamk.best$nc,"\n") #cat表示連接
plot(pam(d,pamk.best$nc),main="") #pam(x,k)將數據x划分為k個聚類
#這兩個組成部分解釋了100%的點變異性
#此圖表示最佳平均輪廓寬度簇類數估計,從簇類數估計看,簇類設置為4類為最佳
#步驟3 聚類結果展示及其可視化
par(mfrow=c(1,1)) c1<-kmeans(d,pamk.best$nc) c1
plot(d,col=c1$cluster)+points(c1$centers,col=3:6,pch=12,cex=1) #plot(d,col=c1$cluster) 畫出聚類結果 #points(c1$centers,col=3:6,pch=12,cex=1) 畫出每個聚類的中心,且設置顏色col,設置參數控制符號(圖中的四方格)pch,設置控制符號和文字的大小cex
案例1:k-means聚類算法在NCI60數據集上的應用
#NCI60數據集由64個細胞系的6830個基因表達數據構成,每個細胞系都有一個標簽變量記錄了其癌細胞的類型
library(ISLR) nci.labs<-NCI60$labs nci.data<-NCI60$data #在進行 PCA 和聚類分析時,由於是無指導約學習,不使用癌細胞的類型特征,在 PCA和聚類分析之后,可以用這些特征檢驗無指導學習的結果與癌細胞類型的匹配度。 dim(nci.data)
nci.labs[1:4] #查看癌細胞系的類型
table(nci.labs) #列出癌細胞的類型
set.seed(2) km.out<-kmeans(sd.data, 4, nstart=20) #k均值聚類法 km.clusters<-km.out$cluster table(km.clusters,hc.clusters)
案例2:k-means聚類算法在iris數據集上的應用
#鳶尾花數據集
require("stats") model<-kmeans(x=subset(iris,select = -Species),centers = 3) table(iris$Species,model$cluster,dnn=c("Actual","predicted"))
#如何確定聚類數
聚類就像切西瓜,切幾瓣真的很隨意,但是我們也可以使用一些方法評估一下應該聚幾類,比如輪廓系數,它結合了內聚度和分離度兩種因素,即同時考察了組內相似性和組間差異性,可見輪廓系數的值介於[-1,1],越趨近於1代表內聚度和分離度都相對較優。
#(1)輪廓系數
library(cluster) asw<-numeric(20) #生成一個序列 for(k in 2:20){ #測試聚類2-20的可能性 asw[[k]]<-pam(subset(iris,select = -Species),k)$silinfo$avg.width } k.best<-which.max(asw) #找出最大的聚類數 cat("通過輪廓系數(silhouette)估計的最佳聚類數:",k.best,"\n") #輸出最佳聚類數
#(2)中心划分法(PAM)
library(fpc) library(cluster) pamk.best<-pamk(subset(iris,select = -Species)) cat("通過中心化分法估計的最佳聚類數:",pamk.best$nc,"\n") #輸出最佳聚類數