install.packages("gutenbergr")
install.packages("dplyr")
install.packages("tidytext")
install.packages("wordcloud")
install.packages("ggplot2")
install.packages("stringr")
install.packages("tidyr")
install.packages("igraph")
install.packages("ggraph")
install.packages("syuzhet")Исследование романов Джейн Остин
Что скрывается под обложкой романов ‘Emma’, ‘Sense and Sensibility’и ’Pride and Prejudice’?
1 Цель и описание проекта
Главная цель моего проекта - изучить литературный язык Джейн Остин и особенности её письма с помощью методов языка R (Classicus 2024). Для этого я проведу несколько мини-исследований:
- во-первых, проведу частотный анализ текста - с токенизацией, но без лемматизации, так как в силу специфики английского языка мы можем потерять различные слова (например die - “умирать” и dying - “умирает”/умирающий”), если приведем все к начальному виду. Это поможет нам сделать некоторые выводы о свойственном Остин лексиконе, а также, потенциально, позволит заметить некоторые общие паттерны в её методе.
- во-вторых, мы построим “линии встречаемости” героев романа, из чего можно будет сделать вывод о “важности” и месте персонажей в сюжетах.
- в-третьих, по аналогии с выявлением самых частотных слов, мы проведем анализ частотности биграмм в романах
- в-четвертых, мы проведем семантический анализ текста с помощью подхода NRC, который позволяет не только выявить положительность/негативность текста, но и извлечь конкретные эмоциональный фон книг.
2 До начала работы
На нулевом этапе работы необходимо подключить все библиотеки, которые понадобятся нам для проведения исследования. В моем случае это следующий список: gutenbergr (с помощью него получены тексты); wordcloud, ggplot2, igraph и ggraph (для визуализации результатов); dplyr, tidytext, stringr, tidyr и syuzhet (для корректной работы методов)
После загрузки необходимо все подключить
library(gutenbergr)
library(dplyr)
library(tidytext)
library(wordcloud)
library(udpipe)
library(ggplot2)
library(stringr)
library(tidyr)
library(igraph)
library(ggraph)
library(syuzhet)3 Слово отражает мысль: непонятна мысль — непонятно и слово
Слова — такие невинные и бессильные, какими они являются, стоя в словаре, какими могущественными для добра и зла они становятся в руках того, кто знает, как их сочетать!
— Натаниэль Хоторн
Скачаем и токенизируем тексты трех романов Джейн Остин: “Эмма” (Austen 1816), “Гордость и предубеждение” (Austen 1813) и “Разум и чувства” (Austen 1811) (первый роман имеет идентификационный номер gutenberg_id = 158, второй - 161, а третий - 1342).
books <- gutenberg_download(c(158, 161, 1342), meta_fields = "title", mirror = "http://mirrors.xmission.com/gutenberg/")
books |>
unnest_tokens(word, text) |>
count(title, word, sort = TRUE) |>
anti_join(stop_words) |>
group_by(title) |>
slice(1:20) |>
ungroup() |>
mutate(word = reorder_within(x = word, by = n, within = title)) |>
ggplot(aes(n, word))+
geom_col()+
facet_wrap(~title, scales = "free")+
scale_y_reordered()Рассмотрим гистограммы по отдельности и подметим некоторые их общие и индивидуальные особенности:
Что мы видим? Первые места по употреблению во всех трех романах занимают имена, фамилии и звания главных героев (emma, elton, harriet в романе “Emma”, elizabeth и darcy - в “Pride and Prejudice”, elinor и colonel - в “Sense and Sensibility”). Однако, есть и интересные особенности:
- во всех трех романах значительное место занимает слово time.
- в лексиконе “Pride and Prejudice” (в силу сюжета) часто используются слова, связанные с семьей: family, sister, dear, father (интересно, что не mother!). Из забавного - видимо, в пакете gutenbergr сохранено издание с иллюстрациями, потому что слово illustration, имеющее к действиям в романе достаточно опосредованное отношение, употребляется часто
- в лексиконе “Emma” есть слова, которые я бы назвала “светскими” или связанными с общественной жизнью: friend, day
- несмотря на романтическую направленность всех трех романов, именно в “Sense and Sensibility” в топ впервые вырывается слово heart
Есть еще один очень удобный и достаточно наглядный метод визуализации наиболее часто встречающихся в тексте слов - облако слов. Построим их для каждого романа.
books |>
unnest_tokens(input = 'text', output = 'word') |>
count(title, word, sort = TRUE) |>
anti_join(stop_words) |>
with(wordcloud(word, n, random.order = FALSE, max.words = 100))Однако это облако слов для общего массива. Сделаем то же самое для каждого романа, отфильтровав в самом начале тексты по названию книги:
4 Герой — это самая короткая профессия на свете
Вот Вам мой читательский совет; когда изображаете горемык и бесталанных и хотите разжалобить читателя, то старайтесь быть холоднее — это даёт чужому горю как бы фон, на котором оно вырисуется рельефнее. А то у Вас и герои плачут, и Вы вздыхаете.
— А.П. Чехов
Наконец, построим “линию времени” - график, показывающий, в каких частях романа появляются (присутствует физически или метафизически) члены семей - главных действующих лиц. Отслеживать это предлагается по фамилии героев:
books |>
filter(title == "Emma") |>
unnest_tokens(word, text) |>
mutate(narrative_time = 1:n()) |>
filter(str_detect(word, "churchill$|fairfax$|knightley$|woodhouse$")) |>
ggplot()+
geom_vline(aes(xintercept = narrative_time))+
facet_wrap(~word, ncol = 1)books |>
filter(title == "Pride and Prejudice") |>
unnest_tokens(word, text) |>
mutate(narrative_time = 1:n()) |>
filter(str_detect(word, "darcy$|bennet$|bingley$|collins$|wickham$")) |>
ggplot()+
geom_vline(aes(xintercept = narrative_time))+
facet_wrap(~word, ncol = 1)books |>
filter(title == "Sense and Sensibility") |>
unnest_tokens(word, text) |>
mutate(narrative_time = 1:n()) |>
filter(str_detect(word, "dashwood$|ferrars$|willoughby$|brandon$")) |>
ggplot()+
geom_vline(aes(xintercept = narrative_time))+
facet_wrap(~word, ncol = 1)Какие выводы, проанализировав получившиеся таймлайны, можно сделать?
В романе “Эмма” появления членов семейств woodhouse и knightley распределены более-менее равномерно по всему роману, появляются в начале и исчезают в конце. С семействами fairfax и churchill ситуация обратная - в середине они появляются/упоминаются сильно чаще, чем в начале и конце, концентрация также увеличивается по мере событий в романе.
В романе “Гордость и Предубеждение” фамилия главных героинь - bennet - распределена неравномерно: очень много упоминаний в начале и в конце, но в середине мы видим “яму”. Противоположную тенденцию мы видим у семейства darcy, представленного, по сути, одним героем - мало упоминающаяся в начале, в середине романа это фамилия сконцентрирована достаточно плотно. Есть свои участки “плотности” и у остальных семейств - в начале романа это bingley, ближе к середине - collins. Интересное наблюдение насчет wickham - в первых двух третьих романа он неразрывно упоминается с Дарси (даже пики совпадают!), в конце же ситуация обратная - пересечений сильно меньше, распределения противоположны.
В романе “Разум и чувства” семейства четко разделились на две группы: “часто упоминаемые” и “редко упоминаемые”. Что-то не очень удивляет - к dashwood все-таки принадлежат все главные героини, поэтому частое упоминание этой фамилии на протяжении всего романа логично, а вот частое употребление willoughby (особенно на фоне редкого упоминания второго героя-возлюбленного, ferrars, и возлюбленного в будущем, brandon) наталкивает на мысль, что его ветка содержит гораздо больше страстей и событий.
5 Биграммы
В этот раз обойдемся без цитаты, потому что такое понятие как биграммы в представлении не нуждается!
Наконец, построим биграммы для каждого из романов по отдельности и для трех романов совместно:
bigrams_graph <- books |>
unnest_tokens(bigram, text, token = "ngrams", n = 2) |>
drop_na() |>
separate(bigram, c("word1", "word2"), sep = " ") |>
filter(!(word1 %in% stop_words$word) & !(word2 %in% stop_words$word)) |>
count(word1, word2, sort = TRUE) |>
filter(n > 20) |>
graph_from_data_frame()
ggraph(bigrams_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)bigrams_graph <- books |>
filter(title == 'Emma') |>
unnest_tokens(bigram, text, token = "ngrams", n = 2) |>
drop_na() |>
separate(bigram, c("word1", "word2"), sep = " ") |>
filter(!(word1 %in% stop_words$word) & !(word2 %in% stop_words$word)) |>
count(word1, word2, sort = TRUE) |>
filter(n > 20) |>
graph_from_data_frame()
ggraph(bigrams_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)bigrams_graph <- books |>
filter(title == 'Pride and Prejudice') |>
unnest_tokens(bigram, text, token = "ngrams", n = 2) |>
drop_na() |>
separate(bigram, c("word1", "word2"), sep = " ") |>
filter(!(word1 %in% stop_words$word) & !(word2 %in% stop_words$word)) |>
count(word1, word2, sort = TRUE) |>
filter(n > 20) |>
graph_from_data_frame()
ggraph(bigrams_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)bigrams_graph <- books |>
filter(title == 'Sense and Sensibility') |>
unnest_tokens(bigram, text, token = "ngrams", n = 2) |>
drop_na() |>
separate(bigram, c("word1", "word2"), sep = " ") |>
filter(!(word1 %in% stop_words$word) & !(word2 %in% stop_words$word)) |>
count(word1, word2, sort = TRUE) |>
filter(n > 20) |>
graph_from_data_frame()
ggraph(bigrams_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)Интересное замечание - судя по тому, насколько часто (и во всех трех романах, во всевозможных комбинациях) появляется слово miss, и ни разу не появляется слово mister (хотя есть sir, гендерно нейтральное dear, звание colonel и явные мужские имена), можно сделать вывод о гендерном составе героев романов и их возрасте и семейном положении. Занимательно и то, что в большинстве своем биграммы - это имена собственные, обращения (lady catherine, frank churchill), глагол есть лишь один (emma | elizabeth | marianne - cried). Биграмму _copyright - 1894 комментировать не буду - издержки источника)
6 Сентиментальный анализ
Наконец, хочется что-то понять про эмоции, которые в романе так или иначе проявляются. Для этого объединим тексты в отдельные файлы и найдем для всех возможных слов сентиментальный анализ по методу NRC (на эту мысль меня натолкнули следующие материал: Silge (2016)). В итоге получились следующие кривые “эмоциальности”.
emma <- books |>
filter(title =='Emma') |>
group_by(linenumber = ceiling(row_number() / 10)) |>
summarize(text = str_c(text, collapse = " "))
pp <- books |>
filter(title =='Pride and Prejudice') |>
group_by(linenumber = ceiling(row_number() / 10)) |>
summarize(text = str_c(text, collapse = " "))
ss <- books |>
filter(title =='Sense and Sensibility') |>
group_by(linenumber = ceiling(row_number() / 10)) |>
summarize(text = str_c(text, collapse = " "))
emma_sentiment <- data.frame(cbind(linenumber = emma$linenumber, sentiment = get_sentiment(emma$text, method = "nrc")))
pp_sentiment <- data.frame(cbind(linenumber = pp$linenumber, sentiment = get_sentiment(pp$text, method = "nrc")))
ss_sentiment <- data.frame(cbind(linenumber = ss$linenumber, sentiment = get_sentiment(ss$text, method = "nrc")))
plot(emma_sentiment,
type="l",
main="Emma Plot Trajectory",
xlab = "Narrative Time",
ylab= "Emotional Valence")
abline(h = 0, col = "red", lty = 2)
plot(pp_sentiment,
type="l",
main="Pride and Prejudice Plot Trajectory",
xlab = "Narrative Time",
ylab= "Emotional Valence")
abline(h = 0, col = "red", lty = 2)
plot(ss_sentiment,
type="l",
main="Sense and Sensibility Plot Trajectory",
xlab = "Narrative Time",
ylab= "Emotional Valence")
abline(h = 0, col = "red", lty = 2)Все более-менее одинаково - перепады сильные, настрой в большинстве отрывков положительный, есть выбросы - крайне эмоциональные моменты со знаком “плюс” и “минус”. В общем, можно явно сказать, что это не трагедии о тяжелой судьбе незамужних дев в начале девятнадцатого века, а достаточно легкие, эмоциональные истории, всегда заканчивающиеся на хорошей ноте.
Из индивидуальных замечаний:
- В романе “Эмма” эмоциональный тон в самом начале идет в плюс, а вот финальное значение тона находится даже ниже (в среднем), чем в первых отрывках. Обратная ситуация в двух других романах - начинаясь с некоторого эмоционального падения, к концу ситуация исправляется. То есть, несмотря на волновую структуру всех трех прямых, романы как бы находятся в противофазе.
- Самый “негативный” роман (или, если быть точнее, “бурный”) - “Гордость и Предубеждение” - в нем больше всего чаше всего кривая переходит в отрицательные значения
7 Распределение эмоций в романах
… но на всякий случай, дополнительно, давайте все же убедимся в этом и посмотрим не на общий эмоциональный (позитивный/негативный) фон, а более подробно - на распределение различных эмоций в романе. Поможет нам в этом то, что мы использовали именно метод nrc:
nrc_data_emma <- get_nrc_sentiment(str_c(emma$text, collapse = " "))
barplot(
sort(colSums(nrc_data_emma[, 1:8])),
horiz = TRUE,
cex.names = 0.7,
las = 1,
main = "Emotions in Emma", xlab="Percentage"
)nrc_data_pp <- get_nrc_sentiment(str_c(pp$text, collapse = " "))
barplot(
sort(colSums(nrc_data_emma[, 1:8])),
horiz = TRUE,
cex.names = 0.7,
las = 1,
main = "Emotions in Pride and Prejudice", xlab="Percentage"
)nrc_data_ss <- get_nrc_sentiment(str_c(ss$text, collapse = " "))
barplot(
sort(colSums(nrc_data_emma[, 1:8])),
horiz = TRUE,
cex.names = 0.7,
las = 1,
main = "Emotions in Sense and Sensibility", xlab="Percentage"
)Все результаты подсчетов можно свести вот в такую таблицу:
| Emotion | Emma | Pride and Prejudice | Sense and Sensibility |
|---|---|---|---|
| Anger | 314 | 314 | 299 |
| Anticipation | 327 | 310 | 316 |
| Disgust | 233 | 227 | 214 |
| Fear | 364 | 336 | 332 |
| Joy | 303 | 288 | 293 |
| Sadness | 348 | 321 | 318 |
| Surprise | 166 | 166 | 170 |
| Trust | 456 | 439 | 439 |
Интересно, что совпадают не просто распределения и некоторая относительная частотность (чего больше\меньше), но и даже абсолютная!