library(readr)
library(tidyverse)
library(xml2)
library(dplyr)
library(tidytext)
library(tokenizers)
library(udpipe)
library(rvest)
library(igraph)
library(ggraph)
library(stopwords)
library(wordcloud)
<- c("#66c2a5",
pal "#fc8d62", "#8da0cb", "#e78ac3", "#ffd92f", "#a6d854")
Исследование жанровых особенностей травелога статистическими методами
На текстах А.Радищева “Путешествие из Петербурга в Москву”, В.Ерофеева “Москва - Петушки”, В.Аксенова “Дикой”
Описание работы
В данной работе представлен компаративный анализ произведений А.Н. Радищева, В.П. Аксенова, Вен.В. Ерофеева колличественными и статистическими методами с целью поиска возможных сходств и различий в реализации сюжетной специфики травелога.
Установка необходимых пакетов и создание общих переменных
Подготовка датасета
Для решения разных задач было решено подготовить 2 датасета: через POS-тэггинг и простую токенизацию из пакета tidyverse. Необходимые тексты лежат на разных сайтах, поэтому мы создадим 3 функции для каждого текста, применим их к каждому сайту и почистим данные.
Парсинг “Путешествия” Радищева
слова “парсинг” и “Радищев” еще никогда не были так одновременно далеко и близко друг к другу
# функция для парсинга текста Радищева
<- function(url) {
get_text_radishev read_html(url) |>
html_elements(".mw-parser-output") |>
html_text2()
}# ссылка на сайт с текстом Радищева
<- 'https://ru.wikisource.org/wiki/Путешествие_из_Петербурга_в_Москву_(Радищев)'
url_radishev # применим функцию
<- map(url_radishev, get_text_radishev)
get_radishev # создадим таблицу с именем автора, названием произведения и текстом, а также немного почистим текст.
<- tibble(
radishev_tbl author = c('Александр Радищев'),
name = c('Путешествие из Петербурга в Москву'),
text = get_radishev[[1]]
%>%
) separate('text', into = c('else', 'text'), sep = "М. К.Любезнейшему другу.") %>%
select(-'else')
То же самое проделаем и с оставшимися двумя авторами
Парсинг “Москвы - Петушков” Ерофеева
<- function(url) {
get_text_erofeev read_html(url) |>
html_elements("#maintext") |>
html_text2()
}
<- 'https://opentextnn.ru/man/erofeev-venedikt-moskva-petushki-pojema/'
url_erofeev <- map(url_erofeev, get_text_erofeev)
get_erofeev
<- tibble(
erofeev_tbl author = c('Венедикт Ерофеев'),
name = c('Москва - Петушки'),
text = get_erofeev[[1]]
%>%
) separate('text', into = c('else', 'text'), sep = "автора\n") %>%
select(-'else')
Парсинг “Дикого” Аксенова
<- function(url) {
get_text_aksenov read_html(url) |>
html_elements("#main") |>
html_text()
}
<- "https://flibusta.club/b/175705/read"
url_aksenov <- map(url_aksenov, get_text_aksenov)
get_aksenov
<- tibble(
aksenov_tbl author = c('Василий Аксенов'),
name = c('Дикой'),
text = get_aksenov[[1]]
%>%
) # эту некрасивую конструкцию пришлось использовать, только потому что именно она дает самый чистый результат
separate('text', into = c('else', 'text'), sep = "\nЧитать онлайн Дикой бесплатно\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t1") %>%
select(-'else') %>%
separate('text', into = c('text', 'else'), sep = "1965") %>%
select(-'else')
Мы получили 3 таблицы с одинаковыми столбцами и разными значениями. Теперь соединим все вместе. Это и будет нашим итоговым датасетом.
<- rbind(radishev_tbl, erofeev_tbl, aksenov_tbl) dataset_travelogue
Создание токенизированных датасетов
POS-теггинг
Для этого типа токенизации была выбрана модель ‘russian-syntagrus’. Мы скачали и загрузили модель и с ее помощью аннотировали наш датасет. Результат оформили в таблицу.
#имена для doc_id
<- c('Александр Радищев', 'Венедикт Ерофеев', 'Василий Аксенов')
names_authors # скачиваем модель в рабочую директорию
udpipe_download_model(language = 'russian-syntagrus')
# загружаем модель
<- udpipe_load_model(file = "russian-syntagrus-ud-2.5-191206.udpipe")
russian_syntagrus # аннотируем
<- udpipe_annotate(russian_syntagrus, dataset_travelogue$text, doc_id = names_authors) travelogue_annotate
# готовая таблица POS
<- as_tibble(travelogue_annotate) |>
dataset_pos select(-paragraph_id)
Токенизация через unnest_tokens
Мы сделали простую токенизацию, почистили результат (по заданному корпусу стоп-слов, а также по объедиденному из разных источников корпусу стоп-слов).
<- dataset_travelogue |>
dataset_unnest_first unnest_tokens(word, text) %>%
select(-name)
# лишние слова в анти джоин
<- c("снова", "сразу", "этих", "равно", "тому", "твоего", "токмо", "нашего", "ныне", "свое", "почто", "наших", "сие", "г", "весь", "таки", "очень", "сего", "своем", "се", "столь", "пусть", "н", "никто", "эта", "едва", "просто", "сей", "сии", "нежели", "например", "толико", "вся", "одна", "паче", "сия", "многие", "две", "сто", "тридцать", "э", "тех", "6", 'r', 'раз', 'стал', 'сем', 'яко', 'пред', 'моим', 'такое', "таким", "дабы", "хотя", "образом", "коль", "скоро", "крайней", "мере", "совершенно", "верно", "итак", "давай", "вещи", "случае", "случаях", "словом", "ибо", "напротив", "стало", "твоему", "поскольку", "значит", "это", "те", "ради", "такое", "сих", "пор", "самом", "деле", "всем", "этим", "всему", "собой", "тобою", "своим", "самого", "обо", "собою", "дело", "обстоит", "обстояло", "конце", "концов")
other_words # переменная с русскими стоп-словами для анти джоин из разных источников
<- c(
stopwords_ru stopwords("ru", source = "snowball"),
stopwords("ru", source = "marimo"),
stopwords("ru", source = "nltk"))
# уберем повторы и упорядочим по алфавиту
<- sort(unique(stopwords_ru))
stopwords_ru # готовый токенизированный датасет
<- dataset_unnest_first %>%
dataset_unnest anti_join(tibble(word = stopwords_ru)) %>%
filter(!word %in% other_words)
Анализ данных
Тематические особенности
Явное жанровое сходство текстов рождает желание изучить различия в их реализации. Кажется, что разумнее всего начать с тематического анализа.
Зададим пул необходимых и ненужных в этом анализе слов.
<- c('NOUN', 'VERB', 'ADJ')
neccessary_tokens <- c('может', 'есть', 'сие', 'быть', 'мог', 'сам', 'нет', 'раз', 'может', 'сказал', 'было', "Пал", 'моего', 'мною', 'моих', 'моей', 'григориан', 'пал', "мою", "дикой") unnecessary_words
И посмотрим на самые частотные слова текстов сначала на облаке слов кадого автора.
Облако слов “Путешествия”
<- dataset_pos %>%
cloud_radishev filter(upos %in% neccessary_tokens) %>%
filter(doc_id == 'Александр Радищев') %>%
count(token, sort = TRUE) %>%
filter(!token %in% unnecessary_words) %>%
head(n = 100)
wordcloud(cloud_radishev$token,
$n,
cloud_radishevscale = c(3, 0,5),
colors = pal)
Преобладание социальной проблематики в радищевском “Путешествии” видно при самом поверхностном взгляде на облако (см. лексемы: власть, право, человек, государь, общество, свобода, правила). При этом, исторически оправданным кажется и вопрос взаимоотношения между “рабом и господином” (см. лексемы велел, барин, земля, господин, крестьяне). Кроме того, легко обнаруживается еще одна группа слов, связанная с духовной жизнью путешественника (сердце, душа, мысли). Это, как нам кажется, соотносится с сентиментальной напраленностью радищевской прозы.
Так, острая чувственность сочеталась у Радищева с элементами просветительского повествования и социальной критики, о которой мы упомянули выше. Идиллия, искомая сентиментальным путешественником в каждом поселении на всем пути из Петербурга в Москву, оказывается миражом, уступая место социальной несправедливости и бедности, о которых несмотря на “душевные терзания” необходимо говорить.
Облако слов “Москвы - Петушков”
<- dataset_pos %>%
cloud_erofeev filter(upos %in% neccessary_tokens) %>%
filter(doc_id == 'Венедикт Ерофеев') %>%
count(token, sort = TRUE) %>%
filter(!token %in% unnecessary_words) %>%
head(n = 100)
wordcloud(cloud_erofeev$token,
$n,
cloud_erofeevscale = c(3, 0,5),
colors = pal)
Warning in wordcloud(cloud_erofeev$token, cloud_erofeev$n, scale = c(3, : глаза
could not be fit on page. It will not be plotted.
Не знаю, стоит ли как-то комментировать обилие словоформ лексемы “выпить”… Однако. Эта категория соседствует с тематической группой, связанной с категорией души и инфернальности (см. лексемы душа, ангелы, господь, любовь). Объясняется ли это постмодернистской направленностью текста - сложно сказать. Но мы явно видим появление новой плоскости восприятия, обнаруживается образ “нетрезвого философа”, серьезные идеи теперь могут стоять рядом с рассуждениями о “бабах” и “выпивке”. (Безруков А.Н. 2015)
Облако слов “Дикого”
<- dataset_pos %>%
cloud_aksenov filter(upos %in% neccessary_tokens) %>%
filter(doc_id == 'Василий Аксенов') %>%
count(token, sort = TRUE) %>%
filter(!token %in% unnecessary_words) %>%
head(n = 100)
wordcloud(cloud_aksenov$token,
$n,
cloud_aksenovscale = c(3, 0.55),
colors = pal)
Это не самый известный текст, поэтому не лишним будет в двух словах описать сюжет: уже пожилой герой едет с визитом на малую родину, по дороге вспоминая множество историй из прошлого. Уже в финальной точке пути - деревне - встречает своего одноклассника, который, оказывается, из подобранного хлама изобрел машину времени, ну и запустил её на досуге у себя в гараже. Противопоставление насыщенной жизни героя и его товарища толкают на всякие рассуждения философского характера.
А вы читали?
Вставные новеллы из жизни героя нашли свое отражение на облаке слов (вспомнил, видел, году, жизнь), что указывает на явную модификацию травелога как жанра. «Чрезмерное» погружение в прошлое, вместо фиксирования путешествия в настоящем размывает границы жанра.(Коновалова Ю.Ю. 2022) Ну и сложно не связать такое явное первенство слова “спросил” с “потерянностью” путешественника во времени из-за своих вечных флэшбэков.
Абсолютная частотность слов
Для наглядной демонстрации и тематического видоизменения жанровой формы травелова, и его кононических особенностей можно воспользоваться следующим графиком.
|>
dataset_unnest filter(!word %in% unnecessary_words) %>%
group_by(author) |>
count(word, sort = TRUE) |>
slice_head(n = 15) |>
ggplot(aes(reorder_within(word, n, author), n, fill = word)) +
geom_col(show.legend = F) +
facet_wrap(~author, scales = "free") +
scale_x_reordered() +
coord_flip() +
labs(x = NULL, y = NULL)
Так, например, заметно, что именно философская тема объединяет все три текста. Не совсем верно переносить опыт бытовой жизни на художественное целое, но, действительно, человек находящийся в дороге, часто оказывается склонен к рефлексии и размышлениям на “извечные” темы. Все герои выбранных нами произведений так или иначе убеждается в кризисном состоянии бытия, а вместе с тем и «в собственном своем кризисном состоянии». Именно дорога создает все условия для зарождения такого рода размышлений, которые уже затем принимают образ того, что беспокоит каждого конкретного путешественника.
Нарративные стратегии
Компаративно тексты будет правильно сравнить и с точки зрения особенностей нарративных стратегий. Под наррацией в контексте жанровой формы травелога при этом мы понимаем способ и формат рассказывания, повествования.
Распределение самых частотных частей речи
# вектор с ненужными частями речи
<- c('PUNCT', 'NUM', 'CCONJ', 'INTJ', 'DET', 'CCONJ', 'SCONJ', 'ADP')
upos_unnec # топ 5 самых частотных частей речи в тексте Радищева
<- dataset_pos %>%
top_upos_radishev filter(!upos %in% upos_unnec) %>%
filter(doc_id == 'Александр Радищев') %>%
count(upos, doc_id) %>%
arrange(-n) %>%
head(n=5) %>%
mutate(relative = round((n / 36742), 3))
# топ 5 самых частотных частей речи в тексте Ерофеева
<- dataset_pos %>%
top_upos_erofeev filter(!upos %in% upos_unnec) %>%
filter(doc_id == 'Венедикт Ерофеев') %>%
count(upos, doc_id) %>%
arrange(-n) %>%
head(n=5) %>%
mutate(relative = round((n / 21706), 3))
# топ 5 самых частотных частей речи в тексте Аксенова
<- dataset_pos %>%
top_upos_aksenov filter(!upos %in% upos_unnec) %>%
filter(doc_id == 'Василий Аксенов') %>%
count(upos, doc_id) %>%
arrange(-n) %>%
head(n=5) %>%
mutate(relative = round((n / 4621), 3))
# соединяем все данные вместе
<- rbind(top_upos_radishev, top_upos_erofeev, top_upos_aksenov) top_upos_all
График для визуализации:
#график распределения частей речи в текстах
%>%
top_upos_all ggplot(aes(doc_id, relative, fill = upos)) +
geom_col() +
scale_fill_manual(values = pal) +
labs(
x = NULL,
y = NULL,
title = "Distribution of the most frequent parts of speech"
)
Вывод: Мы видим явное преобладание существительных над всеми остальными частями речи, причем - во всех текстах. Это как-будто не согласуется с тезисом многих литературоведов о преобладании в травелоге концепта движения, однако несмотря на большое количество диалогов, например, у Ерофеева или множественность остановок и “действий” у Радищева, преобладающая часть речи - все же существительное. Как нам кажется, (если вообще не во всех текстах существительные преобладают) это может быть связана с повышенным вниманием путешественника к миру “внешнему”. Остюда: попытка Радищева описать быть крестьян, стремление уловить овеществленный облик истины Ерофеева и попытка вернуть предметное прошлое у Аксенова. При этом концепт движения ни сколько не умаляется, потому что движение необязательно оказывается связано с глагольными формами (ассоциирующимися с дейсвием), скорее наоборот - травелог позволяет реализовать этот концепт с иключительным преобладанием словоформ, выраженных сущесвительным.
Времена глаголов
Теперь посмотрим на распреледение времен глаголов в текстах.
# таблица с распределение времен глаголов и текстов
<- dataset_pos %>%
veb_count filter(upos == "VERB") %>%
separate(feats, into = c("else", "tense"), sep = 'Tense=') %>%
select(-'else') %>%
filter(!is.na(tense)) %>%
separate(tense, into = c("tense", "else"), sep = 'VerbForm=') %>%
select(-'else') %>%
separate(tense, into = c("tense", "else"), sep = 'Variant=') %>%
select(-'else') %>%
count(tense, doc_id)
# вектор с общим количество токенов для каждого текста
<- veb_count %>%
gr group_by(doc_id) %>%
summarise(total_n=sum(n))
# добавляем эти данные в общую таблицу
<- merge(veb_count, gr, by="doc_id") %>%
veb_count_1 transform(part=n/total_n)
%>%
veb_count_1 ggplot(aes(doc_id, part, fill = tense)) +
geom_col() +
scale_fill_manual(values = pal) +
labs(
x = NULL,
y = NULL,
title = "Distribution of the verb tenses"
)
Выводы
Преобладание прошедшего времени над другими вероятно ни на что нам не указывает. Слишком уж широко употребимы глаголы прошедшего времени в качестве повествовательной доминанты.
Мы видим явный дисбаланс между настоящим и прошедшем временами в тексте Аксенова. Мы уже упоминали о множестве новелл о прошлом героя, включенных в текст, В их описании, вероятно, употреблялось именно прошедшее время. Статистика нам это поддтвердила.
Занимательно и то, что глаголы будущего времени чаще всего появляются у Радищева и Ерофеева. У первого вероятно из-за его нравоучительных рассуждений о будущем страны, а у второго - из-за эскапического стремления убежать в мир идеальный, который отчасти реализуем именно глагольными формами будущего времени.
Воображаемый читатель
Для нас очень важно понятие “воображаемый читатель”, потому что в травелоге его роль особенно ярка. “Воображаемый читатель” часто “существует” как попутчик, проживающий вместе с путешественником все дорожные происшествия.
Так, “воображаемый читатель” часто рассматривается не в роли факультативного элемента, а в роли неизбежного соучастника в создании наррации. Соответственно отношение рассказчика к “воображаемому читателю” может влиять на весь стиль повествования. .
Мы создали таблицу, в которой recipient - относительный процент слов, относящихся к второстепенному герою / читателю (в общем смысле - выражающих концепт “вы”), personality - относительный процент слов, относящихся к самому рассказчику (концепт “я”).
<- c('я', "мой", "себя")
words_personality <- c("ты", "вы", "твой", "ваш")
words_recipient # вектор, хранящий общее кол-во токенов для каждого текста
<- c(32509, 3874, 15994)
number # количество притяжат. мест, 1 лица
<- dataset_pos %>%
r_1 filter(lemma %in% words_personality) %>%
count(doc_id) %>%
mutate(all_words = number) %>%
mutate(personality = round((n/number), 3)) %>%
select(-'n') %>%
select(-all_words)
# количество притяжат. мест, 2 лица
<- dataset_pos %>%
r_2 filter(lemma %in% words_recipient) %>%
count(doc_id) %>%
mutate(all_words = number) %>%
mutate(recipient = round((n/number), 3)) %>%
select(-'n') %>%
select(-all_words)
# общая таблица
<- r_1 %>%
r_1_all left_join(r_2) %>%
mutate(percent = round((recipient / personality), 3))
r_1_all
Выводы:
Путешественник постоянно держит в основе нарратива читательский фокус, соответствует его желаниям и предпочтениям. Это действительно подтверждается довольно высоким процентом слов, относящихся к категории - recipient. Но все же эти значения крайне низки в сравнении с категорией - personality.
У Радищего мы видим самый маленький процент personality из всех авторов. Вероятно, опять же, из-за социального фокуса его наррации. Больше про то, что вокруг и то, как это исправить.
Венечка вроде как эгоист. Всех переплюнул. Но по процентному соотношению - у него вполне себе средний результат: примерно в два раза он себя любит больше чем окружающих. Получается, не эгоист! Но, действительно, всё веничкино путешествие - постепенное зарывание внутрь своего я,
Итог
Не давайте компьютер с установленным R в руки филологам!
Конечно, зависимость некоторых результатов/статистик и идей, рожденных читательским восприятием, существует, но нужно в тысячу раз внимательнее, серьезнее и беспристрастнее подходить к такого рода исследованиям.
Спасибо за внимание!