层次聚类分析
在层次聚类中,起初每一个实例或观测值属于一类。聚类就是每一次把两类聚成新的一类,直到所有的类聚成单个类为止,算法如下:
(1) 定义每个观测值(行或单元)为一类;
(2) 计算每类和其他各类的距离;
(3) 把距离最短的两类合并成一类,这样类的个数就减少一个;
(4) 重复步骤(2)和步骤(3),直到包含所有观测值的类合并成单个的类为止。
层次聚类方法
单联动聚类方法倾向于发现细长的、雪茄型的类。它也通常展示一种链式的现象,即不相似的观测值分到一类中,因为它们和它们的中间值很相像。全联动聚类倾向于发现大致相等的直径紧凑类。它对异常值很敏感。平均联动提供了以上两种方法的折中。相对来说,它不像链式,而且对异常值没有那么敏感。它倾向于把方差小的类聚合。
Ward法倾向于把有少量观测值的类聚合到一起,并且倾向于产生与观测值个数大致相等的类。它对异常值也是敏感的。质心法是一种很受欢迎的方法,因为其中类距离的定义比较简单、易于理解。
层次聚类方法可以用hclust()函数来实现,格式是hclust(d, method=),其中d是通过dist()函数产生的距离矩阵,并且方法包括 "single"、"complete"、"average"、"centroid"和"ward"。
(1)营养数据的平均联动聚类:
data(nutrient, package="flexclust")
row.names(nutrient) <- tolower(row.names(nutrient)) #将行名改为小写(个人习惯)
nutrient.scaled <- scale(nutrient) #标准化为均值为0、方差为1
d <- dist(nutrient.scaled) #27种食物之间的距离采用欧几里得距离,默认为欧几里得距离
fit.average <- hclust(d, method="average") # hclust()做层次聚类,应用的方法是平均联动
plot(fit.average, hang=-1, cex=.8, main="Average Linkage Clustering")
#plot()函数中的hang命令展示观测值的标签(让它们在挂在0下面)
结果分析:树状图应该从下往上读,它展示了这些条目如何被结合成类。每个观测值起初自成一类,然后相距最近的两类(beef braised和smoked ham)合并。其次,pork roast和pork simmered合并,chicken canned和tuna canned合并。再次,beef braised/smoked ham这一类和pork roast/pork simmered这一类合并(这个类目前包含四种食品)。合并继续进行下去,直到所有的观测值合并成一类。高度刻度代表了该高度类之间合并的判定值。对于平均联动来说,标准是一类中的点和其他类中的点的距离平均值。
NbClust包提供了众多的指数来确定在一个聚类分析里类的最佳数目。不能保证这些指标得出的结果都一致。事实上,它们可能不一样。但是结果可用来作为选择聚类个数K值的一个参考。NbClust()函数的输入包括需要做聚类的矩阵或是数据框,使用的距离测度和聚类方法,并考虑最小和最大聚类的个数来进行聚类。它返回每一个聚类指数,同时输出建议聚类的最佳数目。下面的代码清单使用该方法处理营养数据的平均联动聚类。
(2)选择聚类的个数
install.packages("NbClust")
library(NbClust)
devAskNewPage(ask=TRUE)
nc <- NbClust(nutrient.scaled, distance="euclidean", min.nc=2, max.nc=15, method="average")
table(nc$Best.n[1,]) #看分组的支持数
结果分析:这里,四个评判准则赞同聚类个数为2,四个判定准则赞同聚类个数为3,等等。
barplot(table(nc$Best.n[1,])) #画图
结果分析:横坐标是分组数,纵坐标是支持数,(举例:建议分成2组的,有4个支持),可以试着用“投票”个数最多的聚类个数(2、3、5和15)并选择其中一个使得解释最有
意义。下面的代码清单展示了五类聚类的方案。
clusters<-cutree(fit.average,k=5) #分成5组
table(clusters) #分配情况
结果分析:第一类有7个观测值,第二类有16个观测值,等等。
aggregate(nutrient,by=list(cluster=clusters),median) #原始度量
#描述聚类,aggregate()函数用来获取每类的中位数
结果分析:总共是5类,每一类都有一个明显的特征,可以看数值的大小
aggregate(as.data.frame(nutrient.scaled), by=list(cluster=clusters), median) #标准度量
plot(fit.average, hang=-1, cex=.8,
main="Average Linkage Clustering\n5 Cluster Solution") #显示绘图结果
rect.hclust(fit.average, k=5) #rect.hclust()函数用来叠加五类的解决方案
结果分析:sardines canned形成自己的类,因为钙比其他食物组要高得多。beef heart也是单独成类,是因为富含蛋白质和铁。clams类是低蛋白和高铁的。从beef roast到pork simmered的类中,所有项目都是高能量和高脂肪的。最后,最大的类(从mackerel canned到bluefish baked)含有相对较低的铁。