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") #输出最佳聚类数