Извлечение членства/классификации меток из дендрограммы разреза в R (т. е. функция cuttree для дендрограммы)

Я пытаюсь извлечь классификацию из дендрограммы в 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

Есть ли способ либо заставить классификации сопоставляться друг с другом, либо, в качестве альтернативы, извлечь членство в более низких ветвях из объекта dendrogram (возможно, с некоторым умным использованием dendrapply?) в формате, более похожем на то, что дает cutree?


person Oreotrephes    schedule 22.08.2014    source источник


Ответы (3)


Я предлагаю вам использовать функцию cutree из dendextend. пакет. Он включает в себя метод дендрограммы (т.е.: dendextend:::cutree.dendrogram).

Подробнее о пакете можно узнать из его вводной виньетки< /а>.

Я должен добавить, что хотя ваша функция (classify) хороша, есть несколько преимуществ использования cutree из dendextend:

  1. Это также позволяет вам использовать конкретное k (количество кластеров), а не только h (определенную высоту).

  2. Это согласуется с результатом, который вы получите от cutree на hclust (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)

Кстати, на основе этой функции dendextend позволяет пользователю делать более интересные вещи, например, раскрашивать ветки/метки на основе разрезания дендрограммы:

dend1 <- color_branches(dend1, k = 4)
dend1 <- color_labels(dend1, k = 5)
plot(dend1)

введите здесь описание изображения

Наконец, вот еще немного кода для демонстрации других моих моментов:

# 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

Если вы думаете о том, как улучшить эту функцию, исправьте ее здесь:

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

Я надеюсь, что вы или другие люди найдете этот ответ полезным.

person Tal Galili    schedule 25.08.2014
comment
Большое спасибо за ваш ответ и за разработку этого замечательного пакета! - person Oreotrephes; 26.08.2014
comment
Спасибо за добрые слова Oreotrephes. Дайте мне знать, если у вас возникнут какие-либо проблемы или новые функции, которые, по вашему мнению, будут полезны. Бест, Таль - person Tal Galili; 28.08.2014
comment
Есть ли способ извлечь групповые задания из color_branches(dend1, k = 4)? - person user2117258; 29.10.2016

В итоге я создал функцию для этого, используя 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
}

Использование этой функции проясняет, что проблема заключается в том, что 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.
person Oreotrephes    schedule 25.08.2014

Как только вы сделаете свою дендограмму, используйте метод cutree, а затем преобразуйте ее в фрейм данных. Следующий код создает красивую дендрограмму с помощью библиотеки dendextend:

library(dendextend)

# set the number of clusters
clust_k <- 8

# make the hierarchical clustering
par(mar = c(2.5, 0.5, 1.0, 7))
d <- dist(mat, method = "euclidean")
hc <- hclust(d)
dend <- d %>% hclust %>% as.dendrogram
labels_cex(dend) <- .65
dend %>% 
  color_branches(k=clust_k) %>%
  color_labels() %>%
  highlight_branches_lwd(3) %>% 
  plot(horiz=TRUE, main = "Branch (Distribution) Clusters by Heloc Attributes", axes = T)

введите здесь описание изображения

Судя по цветовой схеме, похоже, что кластеры формируются около порога 4. Итак, чтобы получить назначения в фрейме данных, нам нужно получить кластеры, а затем unlist() их.

Сначала вам нужно получить сами кластеры, однако это всего лишь один вектор числа, имена строк являются фактическими метками.

# creates a single item vector of the clusters    
myclusters <- cutree(dend, k=clust_k, h=4)

# make the dataframe of two columns cluster number and label
clusterDF <-  data.frame(Cluster = as.numeric(unlist(myclusters)),
                         Branch = names(myclusters))

# sort by cluster ascending
clusterDFSort <- clusterDF %>% arrange(Cluster)
person Bryan Butler    schedule 27.08.2020