1. Подготовка данных
2. “Радио” на коротких волнах
3.
Цветные радиодетали
Первый вариант книги доступен всем желающим по ссылке.
Cкачиваю текст в формате docx по ссылке в рабочую директорию и
загружаю в окружение с помощью пакета officer. Обрабатываю файл: удаляю
заголовки (строки с особой пометкой в колонке style_name) и название
книги.
library(officer)
library(dplyr)
doc <- read_docx("~/Радио Мартын.docx")
content <- docx_summary(doc) %>%
filter(is.na(style_name)) %>%
slice(14:n())
Задача: проверить гипотезу о том, что в книге
преобладают нестандартно короткие предложения (1-3 слова).
Решение:
Токенизирую по предложениям;
Удаляю ненужные колонки и пустые строки;
Создаю новую колонку word_count, содержащую количество слов в каждом предложении;
Подсчитываю количество предложений для каждого значения
“word_count”.
library(stringr)
library(tidytext)
sentences <- content %>%
unnest_tokens("sentences", "text", token = "sentences") %>%
select(-content_type, -style_name, -level, -num_id) %>%
filter(sentences != "") %>%
mutate(word_count = str_count(sentences, "\\w+"))
sentences_count <- sentences %>%
group_by(word_count) %>%
count()
DT::datatable(sentences_count)
Логарифмическая шкала на графике используется для визуализации данных с широким диапазоном значений. Таким образом, можно четко видеть различия в малых значениях.
library(plotly)
plot_ly(data=sentences_count, x = ~word_count, y = ~n,
type = "scatter", mode = "markers",
marker = list(size = 10,
color = 'black',
line = list(color = 'limegreen',
width = 2))) %>%
layout(title = 'Длина предложений',
xaxis = list(title = "Количество слов", type = "log"),
yaxis = list(title = "Количество предложений", type = "log"))
Вывод: Гипотеза, в целом, подтвердилась:
преобладают предложения длиной в три слова, и, в основном, количество
слов колеблется от 1 до 6.
Чтобы исследовать еще более мелкие компоненты романа (т.е.
- слова), выполняю лемматизацию и частеречную разметку всего текста,
преобразованного в вектор, с помощью модели SynTagRus.
library(udpipe)
#udpipe_download_model(language = "russian-syntagrus")
russian_syntagrus <- udpipe_load_model(file = "russian-syntagrus-ud-2.5-191206.udpipe")
content_vector <- content$text
ann <- udpipe_annotate(russian_syntagrus, content_vector)
martyn_tbl <- as_tibble(ann) %>%
select(-paragraph_id, -sentence, -xpos)
# Исправляю ошибки лемматизации, влияющие на последующие подсчёты:
martyn_tbl <- martyn_tbl %>%
mutate(lemma = case_when(
lemma == "жука" ~ "жук",
lemma == "«сть" ~ "свет",
lemma == "свет»" ~ "свет",
lemma == "дыра»" ~ "дыра",
lemma == "пятна" ~ "пятно",
lemma == "пятное" ~ "пятно",
TRUE ~ lemma
))
Какие прилагательные использовал автор?
adj <- martyn_tbl %>%
filter(upos == "ADJ") %>%
group_by(lemma) %>%
count(sort = T)
DT::datatable(adj[1:30,])
Совместная встречаемость прилагательных, обозначающих цвет, с соседними словами в предложениях:
x <- subset(martyn_tbl, upos %in% c("NOUN", "ADJ"))
cooc <- cooccurrence(x$lemma, skipgram = 1)
knitr::kable(cooc[1:6, ], caption = "Совместная встречаемость (сущ., прил.)")
| term1 | term2 | cooc |
|---|---|---|
| друг | друг | 58 |
| мужчина | женщина | 48 |
| женщина | мужчина | 34 |
| письмо | письмо | 31 |
| почтовый | ящик | 22 |
| время | время | 20 |
Отбираю строки со значением “зеленый” сначала по колонке term_1, затем - по term_2.
# сочетания с зеленый_1 (удаляю колонку со значением "зеленый", переименовываю оставшиеся колонки для последующего корректного объединения таблиц)
green_1 <- subset(cooc, term1 %in% c("зеленый"))
green_1 <- as_tibble(green_1) %>%
select(-term1) %>%
rename("term" = "term2", "cooc1" = "cooc")
# сочетания с зеленый_2
green_2 <- subset(cooc, term2 %in% c("зеленый"))
green_2 <- as_tibble(green_2) %>%
select(-term2) %>%
rename("term" = "term1", "cooc2" = "cooc")
Функция для объединения колонок с частотой совместной встречаемости:
# если число есть только в одной из двух колонок - вставь его в новую;
# если в обеих - вставь бóльшее число.
combine_cooc <- function(cooc1, cooc2) {
if (is.na(cooc1)) {
return(cooc2)
} else if (is.na(cooc2)) {
return(cooc1)
} else {
return(max(cooc1, cooc2))
}
}
Из объединённой таблицы отбираю топ-15 “зеленых” слов.
green <- green_1 %>%
full_join(green_2) %>%
mutate(cooc = mapply(combine_cooc, cooc1, cooc2), .keep = "unused") %>%
arrange(desc(cooc)) %>%
head(15)
И визуализирую результаты с помощью “облака слов”.
library(wordcloud)
par(bg = 'black')
wordcloud(green$term,
green$cooc,
scale = c(3, 1),
min.freq = 1,
colors = 'limegreen'
)
Точно так же ищу “белые” словосочетания:
# сочетания с белый_1
white_1 <- subset(cooc, term1 %in% c("белый"))
white_1 <- as_tibble(white_1) %>%
select(-term1) %>%
rename("term" = "term2", "cooc1" = "cooc")
# сочетания с белый_2
white_2 <- subset(cooc, term2 %in% c("белый"))
white_2 <- as_tibble(white_2) %>%
select(-term2) %>%
rename("term" = "term1", "cooc2" = "cooc")
# объединение двух таблиц
white <- white_1 %>%
full_join(white_2) %>%
mutate(cooc = mapply(combine_cooc, cooc1, cooc2), .keep = "unused") %>%
arrange(desc(cooc)) %>%
head(15)
# облако "белых" слов
par(bg = 'black')
wordcloud(white$term,
white$cooc,
scale = c(4, 1.5),
min.freq = 1,
colors = 'white'
)
И “черные”:
# сочетания с черный_1
black_1 <- subset(cooc, term1 %in% c("черный"))
black_1 <- as_tibble(black_1) %>%
select(-term1) %>%
rename("term" = "term2", "cooc1" = "cooc")
# сочетания с черный_2
black_2 <- subset(cooc, term2 %in% c("черный"))
black_2 <- as_tibble(black_2) %>%
select(-term2) %>%
rename("term" = "term1", "cooc2" = "cooc")
# объединение двух таблиц
black <- black_1 %>%
full_join(black_2) %>%
mutate(cooc = mapply(combine_cooc, cooc1, cooc2), .keep = "unused") %>%
arrange(desc(cooc)) %>%
head(15)
# облако "черных" слов
par(bg = 'limegreen')
wordcloud(black$term,
black$cooc,
scale = c(4.5, 0.5),
min.freq = 1,
colors = 'black'
)
Выводы:
Писатель использует прием лексического повтора для усиления эффекта;
Прилагательное “черный” ассоциируется с тревожным, страшным;
В “белый” окрашены приятные воспоминания;
“Зеленый” сопровождает подпольную деятельность Мартына.