“Радио Мартын”


Оглавление


1. Подготовка данных
2. “Радио” на коротких волнах
3. Цветные радиодетали


1. Подготовка данных


Первый вариант книги доступен всем желающим по ссылке.
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()) 




2. “Радио” на коротких волнах

Задача: проверить гипотезу о том, что в книге преобладают нестандартно короткие предложения (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.


3. Цветные радиодетали



Чтобы исследовать еще более мелкие компоненты романа (т.е. - слова), выполняю лемматизацию и частеречную разметку всего текста, преобразованного в вектор, с помощью модели 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'
          )

Выводы:

  • Писатель использует прием лексического повтора для усиления эффекта;

  • Прилагательное “черный” ассоциируется с тревожным, страшным;

  • В “белый” окрашены приятные воспоминания;

  • “Зеленый” сопровождает подпольную деятельность Мартына.