Анализ Священного писания

Автор

Линев Никита

Дата публикации

19 декабря 2025 г.

Библиотеки


В данном проекте проводится компьютерный анализ библейского текста в испанском переводе, размеченного в формате XML-TEI. Особенность используемого корпуса заключается в детальной разметке прямой речи, включая указание говорящего, адресата и типа коммуникации. Это позволяет рассмотреть текст не только как последовательность слов, но и как структуру речевых актов.

Текстовые данные взяты из проекта XML-TEI Bible (José Calvo Tello), свободно доступного на GitHub.

В первую очередь, загрузим необходимые библиотеки для работы.

library(xml2)
library(dplyr)
library(purrr)
library(tidyr)
library(stringr)
library(tibble)
library(ggraph)
library(igraph)
library(ggplot2)
library(syuzhet)
bible_xml <- read_xml("TEIBible.xml")
ns <- xml_ns(bible_xml)

В качестве минимальной единицы анализа были выбраны стих (<ab type="verse">), так как он представляет собой устойчивую смысловую и структурную единицу библейского текста, а также сегменты прямой речи (<q>) для сохранения связи между уровнем текста и уровнем коммуникации.

На уровне стихов формируем базовый корпус, включающий идентификаторы книги и главы, а также приблизительную длину текста в словах. Эти данные нам нужны в основном для ориентации в самом корпусе.

verses <- xml_find_all(bible_xml, ".//d1:ab[@type='verse']", ns = ns)
verses_tbl <- tibble(
  verse_id = xml_attr(verses, "id"),
  verse_n  = xml_attr(verses, "n"),
  text_raw = xml_text(verses)
) %>%
  mutate(
    chapter_id = str_remove(verse_id, "\\.\\d{3}$"),
    book = str_extract(verse_id, "(?<=b\\.)[A-Z]+"),
    verse_length = str_count(text_raw, "\\b\\w+\\b")
  ) %>%
  relocate(book, chapter_id, .before = verse_id)

Для каждого сегмента прямой речи сохраняется информация о говорящем, адресате и объёме текста. Связь сегмента с конкретным стихом восстанавливается через иерархию XML-документа (книга -> глава -> стих).

speech <- xml_find_all(bible_xml, ".//d1:q", ns = ns)
speech_tbl <- tibble(
  speech_text = xml_text(speech),
  who = xml_attr(speech, "who"),
  to_whom = xml_attr(speech, "toWhom"),
  type = xml_attr(speech, "type")
) %>%
  mutate(
    verse_id = map_chr(speech, ~ xml_attr(xml_find_first(.x, "ancestor::d1:ab", ns = ns), "id")),
    book = str_extract(verse_id, "(?<=b\\.)[A-Z]+"),
    chapter_id = str_remove(verse_id, "\\.\\d{3}$"),
    speech_length = str_count(speech_text, "\\b\\w+\\b")
  ) %>%
  relocate(book, chapter_id, .before = verse_id) 

Попытка измерять долю прямой речи через отношение количества слов прямой речи к общему объёму текста приводит к проблеме двойного учёта, связанной с сегментацией речи внутри стихов. В связи с этим в анализе были использованы показатели интенсивности прямой речи: количество речевых сегментов и суммарный объём речи, нормализованные на число глав.

chapter_stats <- speech_tbl %>%
  group_by(book, chapter_id) %>%
  summarise(
    speech_words = sum(speech_length),
    speech_segments = n(),
    .groups = "drop"
  )

book_stats <- chapter_stats %>%
  group_by(book) %>%
  summarise(
    total_speech_words = sum(speech_words),
    total_segments = sum(speech_segments),
    chapters = n(),
    segments_per_chapter = total_segments / chapters,
    speech_words_per_chapter = total_speech_words / chapters,
    .groups = "drop"
  ) %>%
  filter(!is.na(book))

Полученные данные позволяют сравнивать коммуникативную структуру различных частей Библии.

ggplot(book_stats,
       aes(x = reorder(book, segments_per_chapter),
           y = segments_per_chapter)) +
  geom_col(fill = "firebrick") +
  coord_flip() +
  labs(
    title = "Интенсивность прямой речи по книгам Библии",
    x = "Книга",
    y = "Среднее число речевых сегментов на главу"
  ) +
  theme_minimal()

ggplot(book_stats,
       aes(x = segments_per_chapter,
           y = speech_words_per_chapter,
           label = book)) +
  geom_point() +
  geom_text(check_overlap = TRUE, size = 3) +
  labs(
    title = "Структура прямой речи в книгах Библии",
    x = "Речевых сегментов на главу",
    y = "Слов прямой речи на главу"
  ) +
  theme_minimal()

Диаграмма интенсивности прямой речи показывает, что наибольшее среднее число речевых сегментов на главу наблюдается в книге JOE (Книга пророка Иоиля). Это связано с жанровой спецификой текста: книга построена преимущественно как последовательность пророческих высказываний и обращений, в которых прямая речь играет центральную структурную роль. В отличие от повествовательных книг, где речь встроена в нарратив, в пророческих текстах именно речевые акты формируют основной объём содержания.

Дополнительно была предпринята попытка рассмотреть структуру коммуникации как сеть взаимодействий между говорящими и адресатами. Узлы сети представляют персонажей, а рёбра — акты прямой речи, взвешенные по объёму текста.

edges <- speech_tbl %>%
  filter(book == "GEN" & !is.na(to_whom)) %>%
  separate_rows(to_whom, sep = " ") %>%
  group_by(who, to_whom) %>%
  summarise(weight = sum(speech_length), .groups = "drop")

graph_full <- graph_from_data_frame(edges, directed = TRUE)
node_strength <- tibble(
  node = names(strength(graph_full, mode = "all")),
  strength = strength(graph_full, mode = "all")
)

top_nodes <- node_strength %>%
  arrange(desc(strength)) %>%
  slice_head(n = 15) %>%
  pull(node)

edges_top <- edges %>%
  filter(who %in% top_nodes & to_whom %in% top_nodes)
graph <- graph_from_data_frame(edges_top, directed = TRUE)

ggraph(graph, layout = "fr") + 
  geom_edge_link(aes(width = weight), alpha = 0.5, color = "lightgreen") +
  geom_node_point(size = 5, color = "darkblue") +
  geom_node_text(aes(label = name), repel = TRUE) +
  labs(title = "Сетевой граф прямой речи в Библии") +
  theme_void()

Сетевой граф, построенный на основе прямой речи в книге Бытия, демонстрирует выраженную асимметрию коммуникативной структуры. Наибольшее количество связей и наибольшую суммарную «силу» узлов имеют персонажи с идентификаторами per14 и per4. Это указывает на их центральную роль в коммуникативной сети текста, где они выступают основными источниками и адресатами речевых актов.

genesis_speech <- speech_tbl %>%
  filter(book == "GEN", !is.na(speech_text) & speech_text != "") %>%
  select(who, speech_text)

sentiment_score <- get_nrc_sentiment(genesis_speech$speech_text, language = "spanish")

genesis_sentiment <- bind_cols(genesis_speech, sentiment_score)

sent_by_who <- genesis_sentiment %>%
  group_by(who) %>%
  summarise(
    positive = sum(positive),
    negative = sum(negative),
    net_sentiment = positive - negative,
    .groups = "drop"
  ) %>%
  arrange(desc(abs(net_sentiment)))
sent_by_who %>%
  slice_head(n = 10) %>%
  ggplot(aes(x = reorder(who, net_sentiment), y = net_sentiment, fill = net_sentiment > 0)) +
  geom_col() +
  coord_flip() +
  scale_fill_manual(values = c("TRUE" = "forestgreen", "FALSE" = "firebrick")) +
  labs(
    title = "Сентимент-анализ прямой речи персонажей Бытия (syuzhet NRC, испанский)",
    x = "Персонаж",
    y = "Net-сентимент (положит. − отрицат.)"
  ) +
  theme_minimal()

speech_nonempty <- speech_tbl %>%
  filter(!is.na(speech_text) & speech_text != "")

sentiment_scores <- get_nrc_sentiment(speech_nonempty$speech_text, language = "spanish")

speech_sentiment <- bind_cols(
  speech_nonempty %>% select(book, speech_text),
  sentiment_scores
)

sent_by_book <- speech_sentiment %>%
  filter(!is.na(book)) %>%
  group_by(book) %>%
  summarise(
    positive = sum(positive),
    negative = sum(negative),
    net_sentiment = positive - negative,
    .groups = "drop"
  ) %>%
  arrange(desc(net_sentiment))
top_books <- sent_by_book %>% slice_head(n = 10)

ggplot(top_books, aes(x = reorder(book, net_sentiment), y = net_sentiment, fill = net_sentiment > 0)) +
  geom_col() +
  coord_flip() +
  scale_fill_manual(values = c("TRUE" = "forestgreen", "FALSE" = "firebrick")) +
  labs(
    title = "Net-сентимент прямой речи по книгам Библии (syuzhet NRC, испанский)",
    x = "Книга",
    y = "Net-сентимент (положит. − отрицат.)"
  ) +
  theme_minimal()

Результаты сентимент-анализа прямой речи показывают, что наибольшее положительное значение суммарного net-сентимента наблюдается в книге Псалтырь. Это согласуется с поэтическим и молитвенным характером текста, в котором преобладает лексика, связанная с выражением благодарности, радости и упования.

Подведем итоги! Проведённый анализ показал, что TEI-разметка позволяет исследовать библейский текст на уровне структуры коммуникации. Использование количественных показателей прямой речи выявляет различия между книгами и главами, не затрагивая содержательных или богословских интерпретаций текста.