(Гарри Поттера много не бывает)
Для анализа мной была выбрана первая часть из серии романов о Гарри Поттере.
Цели-задачи:
Текст для анализа был загружен из GitHub - bradleyboehmke/harrypotter - этот пакет предоставляет доступ к полным текстам первых семи книг “Гарри Поттера”. Текст каждого романа получен из Read Vampire Books, частично обработан и готов для анализа.
Для того, чтобы исследовать контекст упоминания главных героев, извлечем из текста биграммы, начинающиеся на “Гарри”/“Рон”/“Гермиона”. Затем создадим таблицы с результатами для каждого из этих персонажей и визуализируем полученные данные.
#Загружаем необходимые пакеты
library(tidytext)
library(dplyr)
library(ggplot2)
library(tidyr)
library(stringr)
library(harrypotter)
library(wordcloud2)
#philosophers_stone - загруженный файл, содержащий вектор из 17 элементов, каждый из которых - отдельная глава
chapters <- philosophers_stone
data <- tibble(chapter = 1:length(chapters), text = chapters)
#токенизируем текст
tokens <- data %>%
unnest_tokens(word, text)
#извлекаем биграммы
bigrams <- tokens %>%
mutate(next_word = lead(word)) %>%
unite(bigram, word, next_word, sep = " ")
my_bigrams <- bigrams %>%
filter(str_starts(bigram, "harry |ron |hermione "))
bigram_counts <- my_bigrams %>%
group_by(chapter, bigram) %>%
summarise(count = n())
#делим все биграммы по персонажам
bigram_counts_harry <- bigram_counts %>%
filter(str_starts(bigram, "harry ")) %>%
split(.$chapter)
bigram_counts_ron <- bigram_counts %>%
filter(str_starts(bigram, "ron ")) %>%
split(.$chapter)
bigram_counts_hermione <- bigram_counts %>%
filter(str_starts(bigram, "hermione ")) %>%
split(.$chapter)
#функция для сортировки
process_table <- function(tbl) {
tbl %>%
arrange(desc(count))
}
#сортируем каждую таблицу
bigram_counts_harry <- lapply(bigram_counts_harry, process_table)
bigram_counts_ron <- lapply(bigram_counts_ron, process_table)
bigram_counts_hermione <- lapply(bigram_counts_hermione, process_table)
#удаляем стоп-слова
data("stop_words")
remove_stop_words <- function(tbl) {
tbl %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!(word1 %in% stop_words$word) & !(word2 %in% stop_words$word)) %>%
unite(bigram, word1, word2, sep = " ")
}
bigram_counts_harry <- lapply(bigram_counts_harry, remove_stop_words)
bigram_counts_ron <- lapply(bigram_counts_ron, remove_stop_words)
bigram_counts_hermione <- lapply(bigram_counts_hermione, remove_stop_words)
#объединяем все таблицы в одну для Гарри
harry_bigrams <- bind_rows(bigram_counts_harry)
#группируем по биграммам, считаем общее количество, перечисляем номера глав
result_harry <- harry_bigrams %>%
group_by(bigram) %>%
summarise(total_count = sum(count), chapters = paste(unique(chapter), collapse = ", ")) %>%
arrange(desc(total_count)) %>%
filter(total_count > 2)
#все то же самое для Рона
ron_bigrams <- bind_rows(bigram_counts_ron)
result_ron <- ron_bigrams %>%
group_by(bigram) %>%
summarise(total_count = sum(count), chapters = paste(unique(chapter), collapse = ", ")) %>%
ungroup() %>%
arrange(desc(total_count))
#оставляем только первые 44 строки, чтобы в облаках слов ниже
#у всех героев было одинаковое количество слов
top_44_ron <- head(result_ron, 44)
Фрагмент таблицы с наиболее частотными парами слов для Гарри:
Полученные таблицы пригодятся ниже для построения облаков слов. Теперь посмотрим, как по ходу книги менялся контекст для Гарри.
#делаем новую таблицу для графика
plot_data <- result_harry %>%
separate_rows(chapters, convert = TRUE) %>%
mutate(bigram = str_replace(bigram, "harry ", "")) %>%
mutate(bigram = factor(bigram, levels = unique(bigram)))
#строим график
ggplot(plot_data, aes(x = chapters, y = bigram, color = total_count)) +
geom_point(size = 5) +
scale_color_gradient(low = "#FFF0F5", high = "darkred") +
scale_x_continuous(breaks = seq(min(plot_data$chapters), max(plot_data$chapters), by = 1)) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
labs(x = "Главы", y = "Биграммы", color = "Количество употреблений")
На графике представлены слова, чаще всего встречающиеся в паре с “Гарри”
(по оси x) и номера глав (по оси Y).
Теперь создадим облака слов с наиболее частыми парами слов для каждого из трех главных персонажей:
#создаем облака слов
result_harry$bigram <- gsub("harry ", "", result_harry$bigram)
colors_harry <- rep(c("DarkGreen", "ForestGreen", "OliveDrab", "SeaGreen", "MediumSeaGreen"), length.out = nrow(result_harry))
wordcloud2(data = result_harry, size = 1.2, color = colors, backgroundColor = "Maroon")
top_44_ron$bigram <- gsub("ron ", "", top_44_ron$bigram)
colors_ron <- rep(c("coral", "darkorange", "orangered", "tomato", "peachpuff"), length.out = nrow(top_44_ron))
wordcloud2(data = top_44_ron, size = 1, color = colors_ron, backgroundColor = "darkgreen")
top_44_hermione$bigram <- gsub("hermione ", "", top_44_hermione$bigram)
colors_hermione <- rep(c("yellow", "gold", "lightgoldenrodyellow", "palegoldenrod", "khaki"), length.out = nrow(result_hermione))
wordcloud2(data = result_hermione, size = 1.5, color = colors_hermione, backgroundColor = "SaddleBrown")
Для Гарри:
Для Гермионы:
Для Рона:
В результате выявления наиболее часто встречающихся с “Гарри” пар слов можно проследить связь между сюжетом и контекстом упоминания героя. Так, в главах, посвященных финальному противостоянию Гарри с Волан-де-Мортом, глаголы, стоящие после “Гарри”, по смыслу соотвтствуют активным действиям, предпринимаемым героем. По биграммам также можно проследить развитие дружбы между Гарри, Роном и Гермионой - главы, в которых описываются ситуации, сплотившие персонажей, сопровождаются наиболее активным упоминанием их имен в парах.
Облака слов, наиболее часто стоящих за именами героев, позволяют выявить характерные черты последних. например, сли у Гермионы на первом месте оказалось основательное “Granger” (у Рона, напротив, фамилия даже не вошла в топ), то у Рона, неожиданно - muttered. Впрочем, это довольно точно характеризует героя в детстве:)