Сеть совместной встречаемости в «Записках о Галльской войне» Цезаря

Author

Денис Брель

Импорт библиотек и загрузка корпуса.

Загружаем необходимые библиотеки.

library(udpipe)
library(igraph)
library(ggraph)
library(ggplot2)
library(visNetwork)
library(dplyr)

Загружаем размеченный корпус. Оставим только существительные.

caesar <- udpipe_read_conllu("https://github.com/locusclassicus/text_analysis_2024/raw/main/files/bg_latinpipe.conllu")
caesar_subset <-  caesar |> 
  filter(upos == "NOUN")

Подсчитаем как часто два слова встречаются вместе в одном предложении.

cooc <- cooccurrence(
  x = caesar_subset,
  term = "lemma",
  group = c("doc_id", "sentence_id")
) |> 
  as_tibble() |> 
  filter(cooc > 20)

DT::datatable(cooc[1:10,])

Построение статической сети

Преобразуем результат в граф.

caesar_g <- graph_from_data_frame(cooc)

deg <- degree(caesar_g)
V(caesar_g)$Узлы <- ifelse(deg >= 6, "Ключевые", "Прочие")
cols <- c(Ключевые = "#C266FF", Прочие = "#aed7a0")

set.seed(2026)
ggraph(caesar_g, layout = "fr") +
  geom_edge_link(color = "grey50", edge_width = 1, edge_alpha = 0.7) +
  geom_node_label(aes(label = name, fill = Узлы), color = "white", size = 3) +
  scale_fill_manual(values = cols) +
  theme_graph(base_family = "Arial") +
  labs(title = "Сеть соупотреблений существительных",
       subtitle = "Ключевые и прочие узлы") 

На графике видим наиболее центральные слова, связанные с другими множеством ребер.

Интерактивная визуализация

library(visNetwork)

nodes <- data.frame(id = unique(c(cooc$term1, cooc$term2)))
nodes$label <- nodes$id
nodes$group <- ifelse(nodes$id %in% V(caesar_g)$name[deg >= 6], "Ключевые", "Прочие")

edges <- data.frame(from = cooc$term1, to = cooc$term2, value = cooc$cooc)

visNetwork(nodes, edges, width = "100%") %>%
  visIgraphLayout(layout = "layout_with_fr") %>%  

  visGroups(groupname = "Прочие", color = list(background = "#aed7a0", border = "#aed7a0")) %>%
  visGroups(groupname = "Ключевые", color = list(background = "#C266FF", border = "#C266FF")) %>%
  visLegend() %>%
  visNodes(shape = "dot", size = 10, shadow = TRUE,
           color = list(highlight = "#FC8D62")) %>%
  visEdges(color = list(color = "#A0A0A0", highlight = "#D95F02"),
           smooth = FALSE) %>%
  visOptions(highlightNearest = list(enabled = TRUE, degree = 1, hover = TRUE),
             nodesIdSelection = TRUE) %>%
  visLayout(randomSeed = 123)