Консенсусные деревья

Компьютерный анализ текстов, занятие 17

Автор

Константин Сатдаров

Дата публикации

2026.02.15

Необходимые библиотеки

Импортируем необходимые для работы пакеты.

library(ape)
library(ggsci)
library(philentropy)
library(phangorn)
library(tidyverse)

Приведение данных в необходимый вид

Для начала необходимо сохранить данные в среду R, чтобы иметь возможность с ними работать.

df <- read.table('table_with_frequencies.txt', # исходный файл
                          header = TRUE, # первая строка - заголовок
                          sep = "", # разделитель - пробел
                          quote = '\"',
                          check.names = FALSE, # сохранить имена столбцов
                          row.names = 1) # первый столбец как имена строк

После этого получившуюся таблицу необходимо преобразоватьв “широкий” формат, то есть сделать названия текстов рядами датасета, а слова - столбцами. Для центрирования данных я также применил в данном задании scale().

# транспонирование
df_wider <- as.data.frame(t(df))

# центрирование
df_st <- df_wider |> 
  scale()

Построение консенсусного дерева

Зададим зерно.

set.seed(20260215)

Построение одного случайного дерева производится за счёт функции get_tree. Используются манхэттенское расстояние и полное присоединение. Засчёт функции построим 100 деревьев и сохраним их в trees_result.

get_tree <- function(df) {
  
  # создание нового датафрэйма с 800 случайными столбцами (size),
  # которые не повторяются (replace)
  X <- df[ , sample(5000, replace = FALSE, size = 800)]
  
  as.phylo(hclust(dist(X, method = 'manhattan'), method = 'complete'))
}

trees_result <- map(1:100, ~get_tree(df_st))

Визуализация

# палитра из "Симпсонов" в количестве 12 цветов
colours <- pal_simpsons()(12)

# вычисляем консенсус
cons <- consensus(trees_result, p = 0.5, rooted = FALSE)

# назначаем авторам цвета из палитры
cols <- tibble(author = str_remove(cons$tip.label, '_.+')) |> 
  mutate(colour = case_when(author == 'Булгаков'  ~ colours[1],
                           author == 'Иванов'  ~ colours[2],
                           author == 'Крюков'  ~ colours[3],
                           author == 'Леонов'  ~ colours[4],
                           author == 'Островский'  ~ colours[5],
                           author == 'Платонов'  ~ colours[6],
                           author == 'Севский'  ~ colours[7],
                           author == 'Серафимович'  ~ colours[8],
                           author == 'Фадеев'  ~ colours[9],
                           author == 'Фурманов'  ~ colours[10],
                           author == 'Шолохов'  ~ colours[11],
                           author == 'Dubia'  ~ colours[12]))

# строим дерево
# параметры поля (полотна) и шрифта
par(mar = c(0, 0, 4, 0), family = 'mono')

# график
plot.phylo(cons,
           type = 'phylogram', # стиль дерева
           use.edge.length = TRUE, # использовать реальную длину ветвей
           edge.width = 2, # толщина ветвей
           node.color = 'black', # цвет узлов дерева
           font = 2, # жирный шрифт
           tip.color = cols$colour, # передача цветовой палитры для авторов
           cex = 1) # размер шрифта

# заголовок
title(main = 'Консенсусное дерево для 12 авторов
      (манхэттенское расстояние, 100 деревьев,
      выборка по 800 слов)',
      cex.main = 1.5, font.main = 2)