# Загрузка и подключение пакетов
library(tidyverse)
library(stylo)
library(ape)
library(purrr)
library(phangorn)
library(RColorBrewer)
set.seed(1234)Консенсусные визуализации стилеметрического анализа «Тихого Дона»
Введение
Атрибуция литературных текстов при помощи количественных методов — важная задача как цифровой филологии, так и прикладной статистики текста. Вопрос авторства романа Михаила Шолохова «Тихий Дон» длительно обсуждался в гуманитарной литературе; количественные подходы (стилометрия) предоставляют эмпирические инструменты для сопоставления стилевых профилей и оценки степени сходства между текстами.В данном исследовании мы применяем классическую методику на базе Burrows’ Delta и её реализацию в пакете stylo, а также дополнительные бутстрэп-процедуры и сетевые визуализации (consensus tree и consensus network), чтобы проиллюстрировать устойчивость стилевых группировок в корпусе и показать, как интерпретировать результаты в литературно-историческом контексте.
Материалы для анализа — табличные частотности (z-оценки), подготовленные в рамках корпуса «Стилеметрические данные “Тихого Дона” и современной ему прозы», подготовленного Б.В. Ореховым.
Материалы и подготовка данных
Исходная таблица table_with_frequencies.txt содержит z-оценки частот слов для текстов корпуса; строки после преобразования рассматриваются как наблюдения (отдельные тексты), а столбцы — как переменные (слова). Формат «тексты × слова» — стандартный для методов расстояний и Delta, поскольку Burrows’ Delta рассчитывается как среднее абсолютное отличие z-оценок между парами текстов по выбранному множеству слов (most frequent words).
# Загрузка данных
data <- read.table("table_with_frequencies.txt",
header = TRUE,
check.names = FALSE,
stringsAsFactors = FALSE,
fill = TRUE)
if(!all(sapply(data[,1], is.numeric))) {
words <- as.character(data[[1]])
data <- data[,-1]
data <- t(data)
colnames(data) <- words
data <- as.data.frame(data)
} else {
data <- as.data.frame(t(data))
}
data[] <- lapply(data, function(x) as.numeric(as.character(x)))Bootstrap Consensus Tree (BCT)
Вызов stylo(..., analysis.type = "BCT", mfw.min = 100, mfw.max = 500, ...) прогоняет серию анализов при различных объёмах MFW (100–500) и для каждой конфигурации строит дерево на основе Delta; затем формируется bootstrap consensus tree — усреднённая по множеству запусков топология, отражающая наиболее стабильные разбиения.
BCT даёт устойчивую, «обобщённую» картину стилевых связей, устраняя чувствительность к конкретному выбору числа MFW. В работах, посвящённых проблеме авторства «Тихого Дона», авторы подчеркивают необходимость репликации при нескольких MFW для оценки устойчивости кластеров: если тома романа и остальные произведения Шолохова консистентно группируются в разных настройках — это сильный эмпирический сигнал в пользу единого авторства.
# ГРАФИК 1 — BCT (Bootstrap Consensus Tree)
bct_result <- stylo(gui = FALSE,
frequencies = data,
analysis.type = "BCT",
mfw.min = 100,
mfw.max = 500,
mfw.incr = 100,
distance.measure = "delta",
consensus.strength = 0.5,
write.png.file = FALSE,
plot.custom.width = 5,
plot.custom.height = 5,
plot.margin = 0.1,
show.labels = TRUE,
label.size = 1.2,
plot.font.size = 12)Полученный график показывает кластеризацию произведений Шолохова. Как “Тихий Дон”, так и остальные произведения расположились рядом на тех же ветвях что говорит об отчетливом стиле автора.
Bootstrap по словам и majority-rule consensus tree (phylogram)
Bootstrap по признакам моделирует неопределённость, связанную с выбором признаков (MFW или другие). Majority-rule consensus выделяет те группировки, которые устойчивы относительно этой неопределённости. Это дополняет BCT, выполняемый в stylo, и служит важным контрольным инструментом: совпадение результатов обоих подходов повышает доверие к выводам.
# Bootstrap-деревья
get_tree <- function(df, ncols = 100) {
cols <- sample(ncol(df), min(ncols, ncol(df)))
X <- scale(df[, cols])
dist_matrix <- dist(X)
tree <- as.phylo(hclust(dist_matrix, method = "ward.D2"))
tree$tip.label <- rownames(df)
return(tree)
}
Ntrees <- 300
trees_list <- map(1:Ntrees, ~get_tree(data, 100))
cons_tree <- consensus(trees_list, p = 0.5, rooted = TRUE)
labels <- cons_tree$tip.label
groups <- ifelse(grepl("_", labels), sub("_.*", "", labels), labels)
uniq_groups <- unique(groups)
pal <- colorRampPalette(brewer.pal(max(3,min(8,length(uniq_groups))), "Dark2"))(length(uniq_groups))
col_map <- setNames(pal, uniq_groups)
tip_cols <- col_map[groups]# ГРАФИК 2 — Consensus Tree (phylogram)
par(mar = c(5,5,5,5))
plot(cons_tree,
type = "phylogram",
tip.color = tip_cols,
cex = 0.8,
main = "Consensus tree (phylogram)")
legend("topright", legend = uniq_groups, fill = pal, cex = 0.7, bty = "n")На данном графике все четыре тома “Тихого Дона” расположились на одной ветке вместе с “Донскими рассказами”. Отдельно, от этой группы образована ветка с “Поднятой целиной”.
Consensus Tree (fan)
Fan-представление — эстетически и визуально удобная форма отображения той же топологии, особенно при большом числе образцов или когда требуется компактно показать расстояния между множеством меток.
# ГРАФИК 3 — Consensus Tree (fan)
par(mar = c(2,2,4,2))
plot(cons_tree,
type = "fan",
tip.color = tip_cols,
cex = 0.7,
main = "Consensus tree (fan)")Тот же результат виден на другой форме данного графика, где большая часть произведений Шолохова также кластеризована на совместных ветвях. “Судьба человека” и “Они сражались за Родину” стоят отдельно, в том числе потому, что эти произведения более позндние, а авторский стиль на протяжении жизни меняется.
Consensus network
Consensus network кодирует все разбиения, которые встречаются в наборе деревьев, и визуализирует их как ребра и четырехугольники Наиболее выраженные четырехугольники указывают на места, где разные подвыборки признаков дают противоречивую древовидную структуру. Сеть помогает диагностировать, где данные «не укладываются» в единую древовидную модель — это важно для литературных корпусов, где взаимное влияние жанра, темы и редакторских правок может приводить к смешанным сигнатурам.
# 6. Консенсусная сеть
class(trees_list) <- "multiPhylo"
cons_net <- consensusNet(trees_list,
prob = 0.3,
rooted = FALSE)
net_tipcols <- tip_cols[match(cons_net$tip.label, labels)]
par(mar = c(5,5,4,5))
plot(cons_net,
type = "2D",
tip.color = net_tipcols,
edge.color = "grey",
edge.width = 0.1,
main = "Consensus network (prob ≥ 0.3)")Как и на предыдущих графиках - тома “Тихого Дона” вместе с “Донскими рассказами”.
Заключение
Как видим все тома “Тихого Дона” практически всегда стоят вместе, и рядом располагаются “Донские рассказы”. “Судьба Человека” и “Они сражались за Родину” обособлены друг от друга и от остальных произведений. Вызвано это разницей во времени написания и жанровыми особенностями. Произведения остальных писателей группируются отдельно, что говорит о том, что все тома “Тихого Дона” писал один и тот же человек - и это был Шолохов.