Как раскрасить ветви в R-дендограмме в зависимости от классов в ней?

Я хочу визуализировать, насколько хорошо работает алгоритм кластеризации (с определенной метрикой расстояния). У меня есть образцы и соответствующие им классы. Чтобы визуализировать, я группирую и хочу раскрасить ветви дендрограммы элементами в кластере. Цвет будет соответствовать цвету, которому соответствует большинство элементов в иерархическом кластере (задается данными\классами).

Пример: если мой алгоритм кластеризации выбрал индексы 1,21,24 как определенный кластер (на определенном уровне), и у меня есть CSV-файл, содержащий номер класса в каждой строке, соответствующий, скажем, 1,2,1. Я хочу, чтобы этот край был окрашен 1.

Пример кода:

require(cluster)
suppressPackageStartupMessages(library(dendextend))
dir <- 'distance_metrics/'
filename <- 'aligned.csv'
my.data <- read.csv(paste(dir, filename, sep=""), header = T, row.names = 1)
my.dist <- as.dist(my.data)
real.clusters <-read.csv("clusters", header = T, row.names = 1)
clustered <- diana(my.dist)
# dend <- colour_branches(???dend, max(real.clusters)???)
plot(dend)

РЕДАКТИРОВАТЬ: еще один пример частичного кода

dir <- 'distance_metrics/' # csv in here contains a symmetric matrix
clust.dir <- "clusters/" #csv in here contains a column vector with classes
my.data <- read.csv(paste(dir, filename, sep=""), header = T, row.names = 1)
filename <- 'table.csv'
my.dist <- as.dist(my.data)
real.clusters <-read.csv(paste(clust.dir, filename, sep=""), header = T, row.names = 1)
clustered <- diana(my.dist)
dnd <- as.dendrogram(clustered)

person borgr    schedule 01.08.2017    source источник
comment
Я вижу, что уже создал способ сделать это, используя color_branches. Пожалуйста, смотрите мой ответ.   -  person Tal Galili    schedule 02.08.2017


Ответы (3)


Атрибуты цвета узлов и ребер могут быть рекурсивно установлены для объектов «дендрограммы» (которые представляют собой просто глубоко вложенные списки) с помощью dendrapply. В пакете cluster также есть метод as.dendrogram для объектов класса "диана", поэтому преобразование между типами объектов происходит незаметно. Используя кластеризацию diana и позаимствовав некоторый код из примера @Edvardoss iris, вы можете создать цветную дендрограмму следующим образом:

library(cluster)
set.seed(999)
iris2 <- iris[sample(x = 1:150,size = 50,replace = F),]
clust <- diana(iris2)
dnd <- as.dendrogram(clust)

## Duplicate rownames aren't allowed, so we need to set the "labels"
## attributes recursively. We also label inner nodes here. 
rectify_labels <- function(node, df){
  newlab <- df$Species[unlist(node, use.names = FALSE)]
  attr(node, "label") <- (newlab)
  return(node)
}
dnd <- dendrapply(dnd, rectify_labels, df = iris2)

## Create a color palette as a data.frame with one row for each spp
uniqspp <- as.character(unique(iris$Species))
colormap <- data.frame(Species = uniqspp, color = rainbow(n = length(uniqspp)))
colormap[, 2] <- c("red", "blue", "green")
colormap

## Now color the inner dendrogram edges
color_dendro <- function(node, colormap){
  if(is.leaf(node)){
    nodecol <- colormap$color[match(attr(node, "label"), colormap$Species)]
    attr(node, "nodePar") <- list(pch = NA, lab.col = nodecol)
    attr(node, "edgePar") <- list(col = nodecol)
  }else{
    spp <- attr(node, "label")
    dominantspp <- levels(spp)[which.max(tabulate(spp))]
    edgecol <- colormap$color[match(dominantspp, colormap$Species)]
    attr(node, "edgePar") <- list(col = edgecol)
  }
  return(node)
}
dnd <- dendrapply(dnd, color_dendro, colormap = colormap)

## Plot the dendrogram
plot(dnd)

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

person Shaun Wilkinson    schedule 02.08.2017
comment
Есть ли общий способ не указывать цвета словами (и, следовательно, не ограничивать заранее определенное количество классов)? - person borgr; 17.08.2017
comment
Конечно, вы можете просто использовать шестнадцатеричный формат RGB #RRGGBB, чтобы указать любой цвет в спектре. Например, попробуйте заменить c("red", "blue", "green") выше на c("#B44682", "#82B446", "#4682B4"). - person Shaun Wilkinson; 18.08.2017
comment
но это все же вручную, нельзя ли использовать радугу или что-то еще без жесткого кодирования названий цветов (словами или в rgb) - person borgr; 20.08.2017
comment
Да, просто замените c("red", "blue", "green") на rainbow(n = length(uniqspp)) - person Shaun Wilkinson; 21.08.2017

Функция, которую вы ищете, — это color_brances из пакета R dendextend, использующая аргументы clusters и col. Вот пример (на примере Шона Уилкинсона):

library(cluster)
set.seed(999)
iris2 <- iris[sample(x = 1:150,size = 50,replace = F),]
clust <- diana(iris2)
dend <- as.dendrogram(clust)

temp_col <- c("red", "blue", "green")[as.numeric(iris2$Species)]
temp_col <- temp_col[order.dendrogram(dend)]
temp_col <- factor(temp_col, unique(temp_col))

library(dendextend)
dend %>% color_branches(clusters = as.numeric(temp_col), col = levels(temp_col)) %>% 
   set("labels_colors", as.character(temp_col)) %>% 
   plot

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

person Tal Galili    schedule 02.08.2017
comment
Я подумал, что это правильное решение, но затем я попробовал его на реальных данных и заметил, что оно останавливается, когда кластер состоит не из одного реального кластера. как бы вы изменили цвет, чтобы он был цветом реального кластера, представленного Мозесом под краем, а не единственным представленным? данные реальной жизни имеют шум и, следовательно, не разделяются так хорошо. или я что-то пропустил? - person borgr; 16.08.2017
comment
Привет, не могли бы вы привести простой пример, чтобы проиллюстрировать проблему? (Я предполагаю, что это ошибка). Если это так, вы можете опубликовать это на github.com/talgalili/dendextend/issues. - person Tal Galili; 29.08.2017
comment
вы также можете видеть это в вашем примере, некоторые из верхних ветвей черные, у меня просто было больше черных... - person borgr; 29.08.2017
comment
Черные ветви потому, что они не принадлежат ни к одному из подкластеров. Это фича, а не баг. - person Tal Galili; 04.12.2017
comment
Что вы могли бы сделать, так это использовать color_branches с k меньшим, чем количество кластеров, которое вы хотели, и оно окрасило бы более высокие ветви для вас (но немного другими цветами) - person Tal Galili; 04.12.2017

есть подозрения что неправильно понял вопрос однако постараюсь ответить: из моих предыдущих целей переписал на примере радужной оболочки

clrs <- rainbow(n = 3) # create palette
clrs <- clrs[iris$Species] # assign colors
plot(x = iris$Sepal.Length,y = iris$Sepal.Width,col=clrs) # simple test colors
# cluster
dt <- cbind(iris,clrs)
dt <- dt[sample(x = 1:150,size = 50,replace = F),] # create short dataset for visualization convenience
empty.labl <- gsub("."," ",dt$Species) # create a space vector with length of names intended for  reserve place to future text labels
dst <- dist(x = scale(dt[,1:4]),method = "manhattan")
hcl <- hclust(d = dst,method = "complete")
plot(hcl,hang=-1,cex=1,labels = empty.labl, xlab = NA,sub=NA)
dt <- dt[hcl$order,] # sort rows for  order objects in dendrogramm
text(x = seq(nrow(dt)), y=-.5,labels = dt$Species,srt=90,cex=.8,xpd=NA,adj=c(1,0.7),col=as.character(dt$clrs))

результат

person Edvardoss    schedule 01.08.2017
comment
Спасибо за ответ, но я ищу раскраски на кластерах\ребрах\линиях. Не только по названиям галочек\ярлыков. Вопросы заключаются в том, как выбрать раскраску, используя имя метки (например, цвет по наиболее частому цвету метки в кластере). - person borgr; 01.08.2017