R语言拥有大量和聚类分析相关的函数,在这里我主要会和大家介绍K-means聚类、层次聚类和基于模型的聚类。
1. 数据预处理
在进行聚类分析之前,你需要进行数据预处理,这里主要包括缺失值的处理和数据的标准化。我们仍然以鸢尾花数据集(iris)为例进行详细讲解:
代码语言:javascript复制# 数据预处理
mydata <- iris[,1:4] # 只提取前4列数据,不包括类别这个变量
mydata <- na.omit(mydata) # 删除缺失值
mydata <- scale(mydata) # 数据标准化
2. K-means聚类
在聚类分析中,K-means聚类算法是最常用的,它需要分析者先确定要将这组数据分成多少类,也即聚类的个数,这个通常可以用因子分析的方法来确定。比如我们可以用“nFactors”包的函数来确定最佳的因子个数,将因子数作为聚类数,不过关于聚类个数的确定还要考虑数据的实际情况与自身需求,这样分析才会更具有现实意义。 另外,我们也可以通过绘制碎石图来确定聚类个数,这和主成分的思想相似。
代码语言:javascript复制# 利用碎石图确定聚类个数
wss <- (nrow(mydata)-1)*sum(apply(mydata,2,var)) # 计算离均差平方和
for (i in 2:15) wss[i] <- sum(kmeans(mydata,
centers=i)$withinss) #计算不同聚类个数的组内平方和
plot(1:15, wss, type="b", xlab="Number of Clusters",
ylab="Within groups sum of squares") # 绘图
一般我们需要控制组内平方和的值要小,同时聚类的个数也不能太多,所以从图中可以看出聚类个数定在2~3比较好。
代码语言:javascript复制# K-Means聚类分析
fit1 <- kmeans(mydata, 3) # 设定聚类个数为3
# 获取聚类均值
aggregate(mydata,by=list(fit1$cluster),FUN=mean) # aggregate()是一个分类汇总函数
从上面的结果中我们可以看出不同类别的各变量均值,从而对各类的特征有总体的了解,比如第2类是花瓣和花萼都普遍偏大的一类。
代码语言:javascript复制# 返回聚类的结果
res <- data.frame(mydata, fit1$cluster)
大家可以拿返回的聚类结果和真实分类对比一下,看看此次聚类效果如何。
3. 层次聚类
R语言提供了丰富的层次聚类函数,这里我给大家简单介绍一下用Ward方法进行的层次聚类分析。
代码语言:javascript复制# Ward层次聚类
d <- dist(mydata, method = "euclidean") # 计算各个样本点之间的欧氏距离
fit2 <- hclust(d, method="ward.D") #进行Ward层次聚类
plot(fit2) # 绘制树状图展示聚类结果
groups <- cutree(fit2, k=3) # 设定聚类个数为3
# 给聚成的3个类别加上红色边框
rect.hclust(fit2, k=3, border="red")
4. 基于模型的聚类
基于模型的聚类方法利用极大似然估计法和贝叶斯准则在大量假定的模型中去选择最佳的聚类模型并确定最佳聚类个数。我们可以使用R包“mclust”的Mclust()函数来实现这种模型聚类分析,同时你可以通过help(mclustModelNames)去查看各类模型的详细信息。
代码语言:javascript复制# 基于模型的聚类分析
library(mclust)
fit3 <- Mclust(mydata)
plot(fit3) # 绘图
summary(fit3) # 输出结果
从上面的结果来看,将总体聚成两类比较合适!
4. 聚类结果形象化展示
代码语言:javascript复制# 聚类结果展示
# 将原数据聚成两类
fit4 <- kmeans(mydata, 2)
# 用前两个主成分绘制聚类图
library(cluster)
clusplot(mydata, fit4$cluster, color=TRUE, shade=TRUE,
labels=2, lines=0)
从图中看,样本被清晰分成两类,结果看起来挺不错的。
经过上述一系列的聚类分析,我们发现:如果仅仅使用花瓣和花萼的数据,鸢尾花数据集聚成两类最好,其中第一类是“setosa”,第二类则是“versicolor”和“virginica”。虽然该数据集自然分类是3类,但我们发现强行分成三类的效果并不好,这主要是因为仅仅利用花瓣和花萼的数据还无法将“versicolor“和”virginica“这两类进行很好的区分。
其实,在之前的判别分析中,我们已经发现”setosa”这一类的判别结果和其余两类均没有重叠,而“versicolor“和”virginica“这两个数据的线性判别的重叠部分较多,不好区分。
最后,如果真正想提高聚类结果和真实分类的接近度,我们通常需要增加有效的变量,这个才是关键!