> library(pacman)
> p_load(dplyr, ggplot2)
k-means 输出为扁平的聚类结果,分层(层次)聚类输出为树状的聚类结果,当数据为多层级结构时适用。
层次聚类(hierarchical clustering)基于簇间的相似度在不同层次上分析数据,从而形成树形的聚类结构,分层级树状图更能展示数据的层级结构,其算法主要为 聚集式 和 分裂式。
聚集式分层聚类:假设每个样本点都是单独的簇类,然后在算法运行的每一次迭代中找出相似度较高的簇类进行合并,该过程不断重复,直到达到预设的簇类个数K或只有一个簇类。该算法具有更广泛的应用。
将各行单独形成一个聚类;
计算各聚类间的距离;
合并相似聚类;
重复步骤 2、3 直至所有行形成一个聚类。
分裂式分层聚类:
与聚集式相反,分裂式初始化所有行在一个聚类后,然后递归分割。
可以简单理解为:每层采用k-means (k=2)。
1 数据准备
> data(GvHD, package = "mclust")
> gvhd <- as_tibble(GvHD.control)
> str(gvhd)
## tibble [6,809 × 4] (S3: tbl_df/tbl/data.frame)
## $ CD4 : num [1:6809] 199 294 85 19 35 376 97 200 422 391 ...
## $ CD8b: num [1:6809] 420 311 79 1 29 346 329 342 433 390 ...
## $ CD3 : num [1:6809] 132 241 14 141 6 138 527 145 163 147 ...
## $ CD8 : num [1:6809] 226 164 218 130 135 176 406 189 47 190 ...
> DataExplorer::profile_missing(gvhd)
## # A tibble: 4 x 3
## feature num_missing pct_missing
## <fct> <int> <dbl>
## 1 CD4 0 0
## 2 CD8b 0 0
## 3 CD3 0 0
## 4 CD8 0 0
2 聚类间的距离
hclust(d, method = "complete", members = NULL)
d:指定用于系统聚类的数据集样本间的距离矩阵,可以利用函数dist()计算得到;
method:类与类之间的距离;
"single":最短距离法,一个类中的点和另一个类中的点的最小距离
"complete":最长距离法,一个类中的点和另一个类中的点的最大距离
"median":中间距离法,一个类中的点和另一个类中的点的平均距离
"average":类平均法,两类每对观测间的平均距离
"centroid":重心法,两类重心之间的距离
"mcquitty":相似分析法
"ward":离差平方和法,基于方差分析思想,如果分类合理,则同类样品间离差平方和应当较小,类与类间离差平方和应当较大。"ward.D", "ward.D2"
members:取值为NULL或长度为d的向量,用于指定每个待聚类的小类别是由几个样本点组成的。
3 实例
> # 标准化
> gvhd.scale <- scale(gvhd)
> gvhd.dist <- dist(gvhd.scale, method = "manhattan")
> gvhd.hclust <- hclust(gvhd.dist, method = "ward.D2")
>
> # 树状图
> # hang 等于数值,表示标签与末端树杈之间的距离,若是负数,则表示标签对齐
> # labels 表示标签,默认是NULL,表示变量原有名称。labels=F表示不显示标签
> plot(gvhd.hclust, col = "#487AA1", col.main = "#45ADA8", col.lab = "#7C8071",
+ col.axis = "#F38630", lwd = 3, lty = 1, sub = "",
+ axes = FALSE, hang = -1, labels = F)
> axis(side = 2, at = seq(0, 8000, 2000), col = "#F38630",
+ lwd = 2, labels = FALSE)
> # 圆形图
> ggtree::ggtree(ape::as.phylo(gvhd.hclust),
+ linetype = "dashed",
+ layout = "circular")
4 剪枝
cutree()函数用于将hcluster()的输出结果进行剪枝,最终得到指定类别的聚类结果,书写格式为:
> cutree(tree, k = NULL, h = NULL)
参数介绍:
tree:指定函数hcluster()的聚类结果;
k:一个整数或向量,用于指定聚类的数目;
h:数字标量或向量,用于指定需要剪枝的树的高度。
> gvhd.cut <- cutree(gvhd.hclust, k = 3)
> table(gvhd.cut)
## gvhd.cut
## 1 2 3
## 4301 1356 1152
5 可视化
> # cmdscale()函数降到2维
> temp <- cmdscale(gvhd.dist, k = 2)
>
> tibble(x = temp[, 1],
+ y = temp[, 2],
+ class = as.factor(gvhd.cut)) %>%
+ ggplot(aes(x, y, col = class)) +
+ geom_point() +
+ stat_ellipse(level = 0.95) +
+ theme_bw() +
+ theme(legend.position = "top")
四维降至二维,所以图形看起来有重叠。
5 练习
用欧氏距离来创建距离矩阵,重复聚类过程,绘制树状图,并与案例比较。
> gvhd.dist2 <- dist(gvhd.scale, method = "euclidean")
> gvhd.hclust2 <- hclust(gvhd.dist, method = "ward.D2")
> cut2 <- cutree(gvhd.hclust2, k = 3)
>
> plot(gvhd.hclust2, col = "#487AA1", col.main = "#45ADA8", col.lab = "#7C8071",
+ col.axis = "#F38630", lwd = 3, lty = 1, sub = "",
+ axes = FALSE, hang = -1, labels = F)
> # 展示剪枝为7类的效果
> rect.hclust(gvhd.hclust2, k = 7)
> axis(side = 2, at = seq(0, 8000, 2000), col = "#F38630",
+ lwd = 2, labels = FALSE)
跟使用曼哈顿距离相比,几乎看不出差别。
# 将剪枝的分类加入数据框
gvhd2 <- mutate(gvhd, hcluster = as.factor(cut2))
ggpairs(gvhd2, aes(col = hcluster), upper = list(continuous = "density"),
lower = list(continuous = wrap("points", size = 0.5)))
从图上看,可能聚为4类更合适。
7 分层聚类的优缺点
优点:
1.能得到多层结果,容易解释。
2.实现比较简单。
缺点:
1.不能自然地处理分类变量。
2.不能选择最佳的聚类数量。
3.对不同尺度的数据敏感。
4.不能用于预测新数据。
5.大型数据集的计算成本很高。
6.对离群值敏感。