Создание дендрограмм вручную: как исправить матрицу «слияния» с недопустимым содержимым в plot.hclust?

Я создаю объект hclust вручную (т.е. создаю список с необходимыми слотами, затем меняю его класс на hclust). Шаблон слияния, высоты бифуркаций, порядок листовых узлов и метки листовых узлов известны. Моя цель (и средство тестирования) - построить результирующую дендрограмму. Я не могу создать объект hclust для печати с моими параметрами.

Компоненты объекта hclust описаны в документации по функции hclust здесь (см. раздел Значение).

Ниже приведен воспроизводимый фрагмент кода R, который я использую для создания и построения дендрограммы.

tree <- list()
tree$merge <- matrix(c( -1,  -7,  # row  1
                        -2,  -6,  # row  2
                        -3, -12,  # row  3
                        -4, -14,  # row  4
                        -5,  -8,  # row  5
                        -9, -11,  # row  6
                       -13, -20,  # row  7
                       -15, -19,  # row  8
                         1,   8,  # row  9
                         2,   5,  # row 10
                         3,   6,  # row 11
                         2, -18,  # row 12
                         1,   3,  # row 13
                         2,   4,  # row 14
                       -10,   7,  # row 15
                       -16, -17,  # row 16
                         1,   2,  # row 17
                        15,  16,  # row 18
                         1,  15), # row 19
                     ncol = 2,
                     byrow = TRUE)
tree$height <- c(0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.11167131, 0.11167131, 0.11167131, 0.12832304, 0.17304035, 0.17304035, 0.17304035, 0.17304035, 0.22965349, 0.22965349, 0.23334799)
tree$labels <- as.character(1:20)
tree$order <- c(1, 7, 15, 19, 3, 12, 9, 11, 2, 6, 5, 8, 18, 4, 14, 13, 20, 10, 16, 17)
class(tree) <- "hclust"
plot(tree)

Каждая строка матрицы tree$merge соответствует бифуркации. Отрицательные целые числа относятся к индексам листовых узлов, тогда как положительные целые числа относятся к существующим кластерам по индексам строк в tree$merge.

Запуск кода приводит к следующему сообщению об ошибке.

Error in plot.hclust(tree) : 'merge' matrix has invalid contents

Эскиз предполагаемого результата показан ниже, где значения heights отмечены дополнительными пунктирными линиями. (Рисунок не в масштабе.)

Предполагаемая дендрограмма


person davnovak    schedule 27.10.2019    source источник
comment
К вашему сведению, взгляните на пакет dendextend для визуализации дендрограммы.   -  person Tal Galili    schedule 29.10.2019


Ответы (1)


Валидность дерева hclust проверяется функцией .validity.hclust. Его исходный код приведен здесь. Посмотрите на строки 121-135.

То, что вы получили ошибку, означает, что ваше дерево недействительно из-за его матрицы merge. В нем есть неуникальные элементы (например, 1 и 2). В правильно построенной матрице merge все элементы уникальны и проходят от -N_obs до N_obs-2 (ноль исключен), где N_obs — (положительное) количество наблюдений. Это проверяется следующим тестом if в коде:

if(identical(sort(as.integer(merge)), c(-(n:1L), +seq_len(n-2L))))
    TRUE
else
    "'merge' matrix has invalid contents"

Из ссылки hclust:

объединить матрицу n − 1 на 2.

Строка i слияния описывает слияние кластеров на шаге i кластеризации. Если элемент j в строке отрицателен, то наблюдение − j было объединено на этом этапе. Если j положительно, то слияние произошло с кластером, сформированным на (более раннем) этапе j алгоритма. Таким образом, отрицательные записи в слиянии указывают на агломерации одиночек, а положительные записи указывают на агломерации не-одиночек.

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

Итак, пересмотрите свой объект hclust. Вот некоторый код, чтобы дать вам представление о том, как выглядит правильный объект hclust:

iris2 <- iris[1:20,-5]
species_labels <- iris[,5]
d_iris <- dist(iris2)
tree_iris <- hclust(d_iris, method = "complete")

Присмотритесь к tree_iris$merge.

ОБНОВЛЕНИЕ

Когда у меня появилось больше времени, я решил исправить ваш код. Я изменил запись merge файла tree. Вот как выглядит рабочий код, воспроизводящий вашу дендрограмму:

tree <- list()
tree$merge <- matrix(c( -1,  -7,  # row  1
                        -2,  -6,  # row  2
                        -3, -12,  # row  3
                        -4, -14,  # row  4
                        -5,  -8,  # row  5
                        -9, -11,  # row  6
                        -13, -20,  # row  7
                        -15, -19,  # row  8
                        1,   8,  # row  9: 1,7,15,19
                        2,   5,  # row 10: 2,6,5,8
                        3,   6,  # row 11: 3,12,9,11
                        10, -18,  # row 12: 2,6,5,8 + 18
                        9,   11,  # row 13:  1,7,15,19 + 3,12,9,11
                        12,   4,  # row 14: row 12 + row 4
                        -10,   7,  # row 15: row 7 + 10
                        -16, -17,  # row 16
                        13,   14,  # row 17: row 13 + row 14 
                        15,  16,  # row 18: row 15 + row 16
                        17,  18), # row 19: row 17 + row 18
                     ncol = 2,
                     byrow = TRUE)
tree$height <- c(0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.06573653, 0.11167131, 0.11167131, 0.11167131, 0.12832304, 0.17304035, 0.17304035, 0.17304035, 0.17304035, 0.22965349, 0.22965349, 0.23334799)
tree$labels <- as.character(1:20)
tree$order <- c(1, 7, 15, 19, 3, 12, 9, 11, 2, 6, 5, 8, 18, 4, 14, 13, 20, 10, 16, 17)
class(tree) <- "hclust"
plot(tree)
person slava-kohut    schedule 27.10.2019
comment
Очень признателен. Подводя итог для других читателей: моя ошибка заключалась в том, что я неоднократно использовал некоторые положительные значения в tree$merge («указывая» на некоторые строки tree$merge в нескольких экземплярах). Однако это никогда не требуется. Например, предположим, что я ссылаюсь на строку 1 в строке 3 и строке 5. Вместо этого в строке 3 я могу ссылаться на строку 1, а в строке I 5 ссылаться на строку 3, которая представляет уже объединенную ветвь. - person davnovak; 28.10.2019