从R中的剪切树形图中提取标签成员资格/分类(即:树状图的cutree函数)

Ore*_*hes 13 r classification cluster-analysis dendrogram dendextend

我正试图从R中的树状图中提取出一个我cut在某个高度的分类.这cutree在一个hclust对象上很容易做到,但我无法弄清楚如何在一个dendrogram对象上做到这一点.

此外,我不能只使用原始hclust中的集群,因为(令人沮丧地),类cutree的编号与类的编号不同cut.

hc <- hclust(dist(USArrests), "ave")

classification<-cutree(hc,h=70)

dend1 <- as.dendrogram(hc)
dend2 <- cut(dend1, h = 70)


str(dend2$lower[[1]]) #group 1 here is not the same as
classification[classification==1] #group 1 here
Run Code Online (Sandbox Code Playgroud)

有没有办法让分类相互映射,或者从dendrogram对象中提取较低的分支成员资格(可能有一些巧妙的使用dendrapply?),格式更像是cutree给出的?

Tal*_*ili 14

我建议您使用dendextend包中的cutree函数.它包括树状图方法(即:).dendextend:::cutree.dendrogram

您可以从其介绍性小插图中了解有关该包的更多信息.

我要补充一点,虽然你的函数(classify)是很好的,有几个优势,利用cutreedendextend:

  1. 它还允许您使用特定的k(簇数),而不仅仅是h(特定的高度).

  2. 这与你从hclust上的cutree得到的结果一致(classify不会).

  3. 它通常会更快.

以下是使用代码的示例:

# Toy data:
hc <- hclust(dist(USArrests), "ave")
dend1 <- as.dendrogram(hc)

# Get the package:
install.packages("dendextend")
library(dendextend)

# Get the package:
cutree(dend1,h=70) # it now works on a dendrogram
# It is like using:
dendextend:::cutree.dendrogram(dend1,h=70)
Run Code Online (Sandbox Code Playgroud)

顺便说一下,在这个函数的基础上,dendextend允许用户做更多很酷的事情,比如基于剪切树形图的颜色分支/标签:

dend1 <- color_branches(dend1, k = 4)
dend1 <- color_labels(dend1, k = 5)
plot(dend1)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

最后,这里有一些代码用于演示我的其他观点:

# This would also work with k:
cutree(dend1,k=4)

# and would give identical result as cutree on hclust:
identical(cutree(hc,h=70)  , cutree(dend1,h=70)  )
   # TRUE

# But this is not the case for classify:
identical(classify(dend1,70)   , cutree(dend1,h=70)  )
   # FALSE


install.packages("microbenchmark")
require(microbenchmark)
microbenchmark(classify = classify(dend1,70),
               cutree = cutree(dend1,h=70)  )
#    Unit: milliseconds
#        expr      min       lq   median       uq       max neval
#    classify  9.70135  9.94604 10.25400 10.87552  80.82032   100
#      cutree 37.24264 37.97642 39.23095 43.21233 141.13880   100
# 4 times faster for this tree (it will be more for larger trees)

# Although (if to be exact about it) if I force cutree.dendrogram to not go through hclust (which can happen for "weird" trees), the speed will remain similar:
microbenchmark(classify = classify(dend1,70),
               cutree = cutree(dend1,h=70, try_cutree_hclust = FALSE)  )
# Unit: milliseconds
#        expr       min        lq    median       uq      max neval
#    classify  9.683433  9.819776  9.972077 10.48497 29.73285   100
#      cutree 10.275839 10.419181 10.540126 10.66863 16.54034   100
Run Code Online (Sandbox Code Playgroud)

如果您正在考虑改进此功能的方法,请在此处进行修补:

https://github.com/talgalili/dendextend/blob/master/R/cutree.dendrogram.R

我希望你或其他人会觉得这个答案很有帮助.


Ore*_*hes 6

我最终创建了一个使用它的功能dendrapply.它不优雅,但它的工作原理

classify <- function(dendrogram,height){

#mini-function to use with dendrapply to return tip labels
 members <- function(n) {
    labels<-c()
    if (is.leaf(n)) {
        a <- attributes(n)
        labels<-c(labels,a$label)
    }
    labels
 }

 dend2 <- cut(dendrogram,height) #the cut dendrogram object
 branchesvector<-c()
 membersvector<-c()

 for(i in 1:length(dend2$lower)){                             #for each lower tree resulting from the cut
  memlist <- unlist(dendrapply(dend2$lower[[i]],members))     #get the tip lables
  branchesvector <- c(branchesvector,rep(i,length(memlist)))  #add the lower tree identifier to a vector
  membersvector <- c(membersvector,memlist)                   #add the tip labels to a vector
 }
out<-as.integer(branchesvector)                               #make the output a list of named integers, to match cut() output
names(out)<-membersvector
out
}
Run Code Online (Sandbox Code Playgroud)

使用该函数可以清楚地表明问题是cut会按字母顺序分配类别名称,而cutree会从左到右分配分支名称.

hc <- hclust(dist(USArrests), "ave")
dend1 <- as.dendrogram(hc)

classify(dend1,70) #Florida 1, North Carolina 1, etc.
cutree(hc,h=70)    #Alabama 1, Arizona 1, Arkansas 1, etc.
Run Code Online (Sandbox Code Playgroud)