library(tidyverse)
library(philentropy)
library(dendextend)
library(stylo)
library(phangorn)
library(ggraph)
library(ggsci)Анализ авторства Тихого Дона методом консенсунсных деревьев
Начало работы и данные
Для работы используется файл с частотностями слов из датасета «Стилеметрические данные “Тихого Дона” и современной ему прозы», подготовленного Б.В. Ореховым.
Для работы используем следующие библиотеки:
Считаем данные из файла и преобразуем в датафрейм, причем исходные строки и столбцы поменяем местами, чтобы в столбцах оказались слова, а в строках - наблюдения:
path <- 'table_with_frequencies.txt'
table <- read.table(path)
table_with_freqs <- table |>
as.data.frame.matrix() |>
t()Подготовительная работа с деревьями
Для создания консенсусного дерева потребуется много отдельных деревьев. Создадим функцию get_tree(df), которая будет создавать дерево на основе выборки из 500 переменных (всего в нашем датафрейме 5000 переменных). Будем использовать манхэттэнское расстояние и метод полносвязной кластеризации (complete linkage):
get_tree <- function(df) {
X <- df[ , sample(5000, replace = FALSE, size = 500)]
dist_mx <- dist(X, method = "manhattan")
res_tree <- as.phylo(hclust(dist_mx, method ="complete"))
}Используем итератор, чтобы создать 400 деревьев, на основе которых будем строить консенсусное дерево:
set.seed(123)
trees_result <- map(1:400, ~get_tree(table_with_freqs))Посмотрим на пример того, как выглядят получившиеся деревья, с которыми мы будем работать:
par(mfrow = c(2, 2), mar = c(0,0,0,0))
walk(trees_result[1:4], plot)Создание консенсусного дерева и график
Строим консенсусное дерево:
set.seed(123)
cons <- consensus(trees_result, p = 0.4, rooted = TRUE)Для последующего оформления графика присваиваем уникальный цвет каждому автору:
cols <- pal_igv()(12)
cols <- tibble(author = str_remove(cons$tip.label, "_.+")) |>
mutate(color = case_when(author == "Булгаков" ~ cols[1],
author == "Иванов" ~ cols[2],
author == "Крюков" ~ cols[3],
author == "Леонов" ~ cols[4],
author == "Островский" ~ cols[5],
author == "Платонов" ~ cols[6],
author == "Севский" ~ cols[7],
author == "Серафимович" ~ cols[8],
author == "Фадеев" ~ cols[9],
author == "Фурманов" ~ cols[10],
author == "Шолохов" ~ cols[11],
author == "Dubia" ~ cols[12]))Строим график и подписываем узлы:
par(mfrow = c(1, 1), mar = c(0,0,0,0))
plot.phylo(cons,
type = "fan",
use.edge.length = TRUE,
edge.width = 1,
node.color = "grey30",
font = 1,
no.margin = FALSE,
label.offset = 0.1,
direction = "rightwards",
plot = TRUE,
lab4ut = "a",
node.depth = 3,
tip.color = cols$color,
cex = 0.7)
# подписываем узлы
nodelabels(text=sprintf("%.2f", cons$node.label),
node=1:cons$Nnode+Ntip(cons),
frame="circle",
bg = "white",
cex = 0.4,
)Краткий комментарий
Мы видим, что произведения Шолохова попадают в два разных кластера (кроме рассказа Судьба человека, который оказывается отдельно). Для нас важно, что Тихий Дон оказывается в тех же двух кластерах, что и другие произведения Шолохова, и не смешивается с произведениями других авторов. В то же время другие авторы оказываются в основном каждый в своем кластере. Отдельно стоит отметить, что Тихий Дон стоит отдельно от произведений Крюкова, которого некоторые исследователи считают настоящим автором этого романа.