[Перевод] Визуализация статических и динамических сетей на R, часть 1

Очень многие системы и явления представимы в виде сетей, т.е. набора объектов и связей между ними. Сеть — не только абстракция, но и наглядный инструмент визуализации данных. Можно отобразить важность того или иного объекта, вес каждой связи, указать ключевые группы элементов, выделить их и подчеркнуть связи между ними. Главная задача визуализации — подать ключевую информацию о свойствах системы или явления максимально легким для восприятия способом. В идеальном случае анализ системы и визуализацию его результатов можно сделать в рамках одного инструмента. R с его обширным набором пакетов позволяет это.

Введение: визуализация сетей


Главное при проектировании визуализации сети — цель, которую нужно достичь. Какие структурные свойства мы хотели бы выделить?
92d8e5453f0543aa8bf59211fe0a1ea7.png

Карты сетей — далеко не единственный инструмент визуализации графов — в некоторых случаях более предпочтительны другие форматы представления сетей, даже простые графики ключевых свойств.
1dcf606d67904c928a7bba6739b9c8c1.png

В картах сетей, как и в других форматах визуализации, есть несколько ключевых настроек, влияющих на конечный результат. Главные — цвет, размер, форма и взаимное расположение.
bf222c7cd8c34645b14577db4f2c14a0.png

Современные представления графов оптимизируют исходя из требований производительности и эстетических соображений. В частности, нужно минимизировать наложение и пересечение ребер, установить одинаковую длину ребер в графе.
11a631c0a6ca499fa058c131c8dbbb88.png

Формат данных, размер и подготовка


В этом руководстве мы в основном будем работать с двумя небольшими массивами данных. Оба содержат информацию о средствах массовой информации. Один содержит сеть гиперссылок и упоминаний в новостных ресурсах. Другой — сеть ссылок между объектами и потребителями массовой информации. Хотя данных в примерах немного, многие идеи сгенерированных визуализаций можно распространить на средние и большие сети. По этой же причине мы редко будем использовать визуальные средства, например, форму символов-вершин: их практически невозможно различить в больших графах. Более того, при отображении очень больших сетей можно даже скрыть ребра, поскольку нужно сосредоточиться на выявлении и отображении групп вершин. Вообще говоря, размер сетей, которые можно визуализировать с помощью R, ограничен только объемом оперативной памяти вашей машины. Но следует подчеркнуть, что во многих случаях визуализация больших сетей в виде гигантского помпона куда менее полезна, чем графики с ключевыми свойствами графа.

В этом руководстве используются несколько ключевых пакетов, которые нужно установить, прежде чем продолжить. Будут упомянуты еще несколько библиотек, но они необязательны, и их можно пропустить. Будут использованы следующие основные библиотеки — igraph (поддерживается Габором Царди и Тамасом Непушем), sna, network (поддерживается Картером Баттсом и командой Statnet) и ndtv (поддерживается Скаем Бендер-деМолль).

install.packages("igraph")
install.packages("network")
install.packages("sna")
install.packages("ndtv")

Набор данных 1: список ребер


Первый набор данных, с которым предстоит работать, состоит из двух файлов: «Media-Example-NODES.csv» и «Media-Example-EDGES.csv» (скачать можно здесь).

nodes <- read.csv("Dataset1-Media-Example-NODES.csv", header=T, as.is=T)
links <- read.csv("Dataset1-Media-Example-EDGES.csv", header=T, as.is=T)


Исследуем данные:

head(nodes)
head(links)
nrow(nodes); length(unique(nodes$id))
nrow(links); nrow(unique(links[,c("from", "to")]))


Обратите внимание, что ребер больше, чем уникальных комбинаций «from»-«to». Это значит, что в данных есть случаи, когда между двумя вершинами более одной связи. Мы свернем все ребра одного типа между двумя узлами, просуммировав их веса с помощью функции aggregate() по «from», «to» и «type»:

links <- aggregate(links[,3], links[,-3], sum)
links <- links[order(links$from, links$to),]
colnames(links)[4] <- "weight"
rownames(links) <- NULL

Набор данных 2: матрица

nodes2 <- read.csv("Dataset2-Media-User-Example-NODES.csv", header=T, as.is=T)
links2 <- read.csv("Dataset2-Media-User-Example-EDGES.csv", header=T, row.names=1)


Исследуем данные:

head(nodes2)
head(links2)


Можно убедиться, что links2 — матрица сопряжения для двусторонней сети:

links2 <- as.matrix(links2)
dim(links2)
dim(nodes2)

Визуализация сетей: первые шаги с igraph


Начнем с превращения исходных данных в сеть igraph. Для этого используем функцию igraph graph.data.frame, которая принимает на вход два блока данных: d и vertices.

  • d описывает ребра сети. В первых двух колонках содержатся идентификаторы начальной и конечной вершины для каждого ребра. В следующих колонках находятся параметры ребра (вес, тип, метка, другое).
  • vertices начинается с колонки идентификаторов вершин. Все следующие колонки интерпретируются как параметры вершины.
library(igraph)

net <- graph.data.frame(links, nodes, directed=T)
net

## IGRAPH DNW- 17 49 -- 
## + attr: name (v/c), media (v/c), media.type (v/n), type.label
##   (v/c), audience.size (v/n), type (e/c), weight (e/n)


Описание объекта igraph начинается с четырех букв:

  1. D или U — для направленного или ненаправленного графа соответственно.
  2. N — для именованного графа (где у узлов есть атрибут name).
  3. W — для взвешенного графа (где у связей есть атрибут weight).
  4. B — для двустороннего графа (где у узлов есть атрибут type).


Следующие два числа (17 49) указывают количество вершин и ребер в графе. В описании также приводятся свойства вершин и ребер, например:

  • (g/c) — свойство-строка на уровне графа
  • (v/c) — свойство-строка на уровне вершины
  • (e/n) — свойство-число на уровне ребра


Также легко получить доступ к вершинам, ребрам и их атрибутам:

E(net)       # Ребра объекта "net"
V(net)       # Вершины объекта "net"
E(net)$type  # Свойство ребра "type"
V(net)$media # Свойство вершины "media"

# Можно работать с матрицей сети и напрямую:
net[1,]
net[5,7]


Теперь, когда есть сеть igraph, можно сделать первую попытку ее построить.

plot(net) # некрасивая картинка!


d4fe423d4f174efdb6fefbaf099db865.png

Получилось не слишком красиво. Давайте начнем улучшать картинку, убрав циклы в графе.

net <- simplify(net, remove.multiple = F, remove.loops = T) 


Вы можете отметить, что можно было использовать simplify, чтобы свернуть несколько ребер в одно, суммируя их веса с помощью команды типа simplify(net, edge.attr.comb=list(Weight="sum","ignore")). Проблема в том, что при совмещении не учитывается тип ребра (в наших данных «hyperlinks» — ссылки и «mentions» — упоминания).

Давайте также уменьшим размер стрелок и уберем метки (установив их в NA):

plot(net, edge.arrow.size=.4,vertex.label=NA)


255c0a43d41248098a87a7ff2999daa6.png

В части 2: шрифты и цвета в графиках R.

© Habrahabr.ru