R根据cutree标签从树形图中获取子树

时间:2018-01-09 11:37:18

标签: r hclust dendextend

我已经聚集了一个大型数据集,发现了6个我有兴趣深入分析的聚类。

我发现了使用hclust和#34; ward.D"方法,我想知道是否有办法获得"子树"来自hclust / dendrogram对象。

例如

library(gplots)
library(dendextend)

data <- iris[,1:4]
distance <- dist(data, method = "euclidean", diag = FALSE, upper = FALSE)
hc <- hclust(distance, method = 'ward.D')
dnd <- as.dendrogram(hc)
plot(dnd) # to decide the number of clusters
clusters <- cutree(dnd, k = 6)

我使用cutree获取数据集中每个行的标签。

我知道我可以通过以下方式获取每个相应集群(例如集群1)的数据:

c1_data = data[clusters == 1,]

有没有简单的方法来获取dendextend::cutree返回的每个相应标签的子树?例如,说我很有兴趣获得

我知道我可以通过

来访问树形图的分支
subtree <- dnd[[1]][[2]

但我怎样才能准确得到与群集1相对应的子树?

我试过了

dnd[clusters == 1]

但这当然不起作用。那么如何根据cutree返回的标签获取子树?

3 个答案:

答案 0 :(得分:2)

=================更新回答

现在可以使用get_subdendrograms中的dendextend解决此问题。

# needed packages:
# install.packages(gplots)
# install.packages(viridis)
# install.packages(devtools)
# devtools::install_github('talgalili/dendextend') # dendextend from github

# define dendrogram object to play with:
dend <- iris[,-5] %>% dist %>% hclust %>% as.dendrogram %>%  set("labels_to_character") %>% color_branches(k=5)
dend_list <- get_subdendrograms(dend, 5)

# Plotting the result
par(mfrow = c(2,3))
plot(dend, main = "Original dendrogram")
sapply(dend_list, plot)

enter image description here

这也可以在热图中使用:

# plot a heatmap of only one of the sub dendrograms
par(mfrow = c(1,1))
library(gplots)
sub_dend <- dend_list[[1]] # get the sub dendrogram
# make sure of the size of the dend
nleaves(sub_dend)
length(order.dendrogram(sub_dend))
# get the subset of the data
subset_iris <- as.matrix(iris[order.dendrogram(sub_dend),-5])
# update the dendrogram's internal order so to not cause an error in heatmap.2
order.dendrogram(sub_dend) <- rank(order.dendrogram(sub_dend))
heatmap.2(subset_iris, Rowv = sub_dend, trace = "none", col = viridis::viridis(100))

enter image description here

=================旧答案

我认为对你有帮助的是这两个功能:

第一个只迭代所有聚类并提取子结构。它要求:

  • 我们想从中获取subdendrograms的dendrogram对象
  • 群集标签(例如,由cutree返回)

返回子树形图列表。

extractDendrograms <- function(dendr, clusters){
    lapply(unique(clusters), function(clust.id){
        getSubDendrogram(dendr, which(clusters==clust.id))
    })
}

第二个执行深度优先搜索以确定群集存在于哪个子树中,以及是否与完整群集匹配则返回该群集。在这里,我们假设集群的所有元素都在一个子索引中。它要求:

  • 树形图对象
  • 群集中元素的位置

返回与给定元素的簇相对应的子树形图。

getSubDendrogram<-function(dendr, my.clust){
    if(all(unlist(dendr) %in% my.clust))
        return(dendr)
    if(any(unlist(dendr[[1]]) %in% my.clust ))
        return(getSubDendrogram(dendr[[1]], my.clust))
    else 
        return(getSubDendrogram(dendr[[2]], my.clust))
}

使用这两个函数,我们可以使用您在问题中提供的变量并获得以下输出。 (我认为第clusters <- cutree(dnd, k = 6)行应为clusters <- cutree(hc, k = 6)

my.sub.dendrograms <- extractDendrograms(dnd, clusters)

绘制列表中的所有六个元素给出所有子树形图

enter image description here

修改

正如评论中所建议的,我添加了一个函数,作为输入采用树形图dend和子树数k,但它仍然使用先前定义的递归函数{{1} }:

getSubDendrogram

5个子结构的测试用例:

prune_cutree_to_dendlist <- function(dend, k, order_clusters_as_data=FALSE) {
    clusters <- cutree(dend, k, order_clusters_as_data)
    lapply(unique(clusters), function(clust.id){    
        getSubDendrogram(dend, which(clusters==clust.id))
    })
}

我使用library(dendextend) dend <- iris[,-5] %>% dist %>% hclust %>% as.dendrogram %>% set("labels_to_character") %>% color_branches(k=5) subdend.list <- prune_cutree_to_dendlist(dend, 5) #plotting par(mfrow = c(2,3)) plot(dend, main = "original dend") sapply(prunned_dends, plot) 使用Tal Galili建议的函数(此处命名为rbenchmark)执行了一些基准测试,结果对于上述DFS方法非常有希望:

prune_cutree_to_dendlist2

enter image description here

答案 1 :(得分:2)

我现在写了函数prune_cutree_to_dendlist来做你要求的事情。我应该在将来的某个时候将它添加到dendextend。

与此同时,这里有一个代码和输出的例子(功能有点慢。使它更快依赖于修剪更快,我不会在不久的将来修复。)

# install.packages("dendextend")

library(dendextend)
dend <- iris[,-5] %>% dist %>% hclust %>% as.dendrogram %>% 
  set("labels_to_character")
dend <- dend %>% color_branches(k=5)

# plot(dend)

prune_cutree_to_dendlist <- function(dend, k) {
  clusters <- cutree(dend,k, order_clusters_as_data = FALSE)
  # unique_clusters <- unique(clusters) # could also be 1:k but it would be less robust
  # k <- length(unique_clusters)
  # for(i in unique_clusters) { 
  dends <- vector("list", k)
  for(i in 1:k) { 
    leves_to_prune <- labels(dend)[clusters != i]
    dends[[i]] <- prune(dend, leves_to_prune)

  }

  class(dends) <- "dendlist"

  dends
}

prunned_dends <- prune_cutree_to_dendlist(dend, 5)
sapply(prunned_dends, nleaves)

par(mfrow = c(2,3))
plot(dend, main = "original dend")
sapply(prunned_dends, plot)

enter image description here

答案 2 :(得分:0)

你是如何使用hclust获得6个集群的?您可以随时剪切树,因此您只需要让cuttree为您提供更多集群:

clusters = cutree(hclusters, number_of_clusters)

如果您有大量数据,这可能不是很方便。在这些情况下,我所做的是手动选择我想要进一步研究的集群,然后仅对这些集群中的数据运行hclust。我不知道hclust中的任何功能允许你自动执行此操作,但它很容易:

good_clusters = c(which(clusters==1), 
                  which(clusters==2)) #or whichever cLusters you want
new_df = df[good_clusters,]
new_hclusters = hclust(new_df)
new_clusters = cutree(new_hclusters, new_number_of_clusters)