Загрузка и первичная обработка данных

library(igraphdata)
library(ggraph)
library(igraph)
library(dplyr)
library(visNetwork)
library(scales)
library(xUCINET)
library(stringr)
library(knitr)
library(ggplot2)
library(ggstatsplot)
library(psych)
library(rstatix)
library(DescTools)

data(enron) 
enron = upgrade_graph(enron)
library(lubridate)
source("C:/Users/79504/Desktop/S&SI/оиад/data analysis technologies/HWnetworks/personalTask.R")
start_date = hw_net_get_start_date(login = "debaranov_1")
# определяем конечную точку месяца
last_date = start_date + dmonths(1)
time = as_date(as_datetime(E(enron)$Time))
# убираем вершины раньше начальной точки и позже конечной
net = enron %>% delete_edges(E(enron)[time < start_date | time > last_date])
# убираем связи вершины самой с собой (согласно данным, иногда люди себя в копию ставят)
net = igraph::simplify(net, remove.multiple = F)
# убираем обособленные вершины
net = net %>% delete_vertices(V(net)[degree(net) == 0])

vertices = as.data.frame(V(net)$Name)
vertices$Email = V(net)$Email
vertices$Note = V(net)$Note
vertices$Name = V(net)$Name

netmatrix = as_adj(net, sparse = F)

netfirst = toVisNetworkData(net)
netfirst$nodes$label = vertices$Name

vertices$Note = as.factor(vertices$Note)

vertices = vertices %>% mutate(position = case_when(
  str_detect(Note, "Manager|Managing|Director") ~ "Middle", 
  str_detect(Note, "Employee|Trader|Lawyer") ~ "Low", 
  str_detect(Note, "NA") ~ "NA", 
  T ~ "Higher"
  ))

vertices$position = ordered(vertices$position, levels = c("Low", "Middle", "Higher", "NA"))
position = vertices$position

Анализируются данные с 2000-11-30 19:30:00 по 2000-12-31 06:00:00

Описание сети

Данная сеть представляет собой сеть переписки сотрудников американской газовой корпорации Enron в период с 2000-11-30 19:30:00 по 2000-12-31 06:00:00.

Всего в сети представлено 117 вершин, каждая из которых является сотрудником компании, отправлявшим в указанный период электронные письма внутри компании, у каждого из которой есть следующие атрибуты:

  • Имя (Name)

  • Адрес электронной почты внутри корпорации (Email)

  • Должность в компании (Note)

  • Кроме того, для удобства анализа сети мы добавили еще один аттрибут - позицию сотрудника внутри компании (Position). Этот аттрибут отражает какое место в иерархии компании занимает тот или иной работник и имеет 3 уровня: низкий (Low, обычные работники, торговцы и юристы), средний (Middle, сотрудники среднего звена, менеджеры и директора) и высокий (Higher, президенты, вице-президенты и другой высший менеджмент).

Каждое из 5445 рёбер сети представляет собой отправку эл. письма от отного сотрудника к другому, каждое ребро имеет следующие атрибуты:

  • Время отправки

  • Тип получателя (одно и то же письмо может быть отправлено нескольким получателям, а также отправлено как копия или скрытая копия)

  • Тема письма

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

Сама сеть является ориентированной.

Целью этого исследования будет изучение структуры сети, определени мер центральностей вершин, разбивка сети на сообщества и интерпретация полученных результатов. Кроме того, поставлены 3 исследовательских вопроса, которые помогут определить а) сотрудники каких позиций в компании имеют более значимое положение в сети, б) кому чаще отправлябт сообщения сотрудники той или иной позиции, равным по позиции или своим руководителям или подчиненным.

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

  • основную, в которой находится подавляющее большинство вершин, при этом можно заметить, что у сети также есть “ядро”, в котором сконцентрировано большое количество высшего менеджмента компании и от которого идут связи с периферией, состоящей в основном из сотрудников среднего и низшего звена. Такая композиция сети показывает, что структура в компании иерархичная, центром являются сотрудники высшего звена.

  • 2 второстепенные, в одной из которых находится 3 вершины, а в другой 5, обе эти части в основном состоят из сотрудников низшего звена.

netfirst$nodes$color = RColorBrewer::brewer.pal(12, "Paired")[position]

netfirst$nodes$position = vertices$position

nodes = netfirst$nodes

legpos = data.frame(label = c("Low", "Middle", "Higher", "NA"), shape = "circle", icon.size = c(25,25,25,25), icon.color = c("#A6CEE3", "#1F78B4", "#B2DF8A",  "#33A02C"))

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой в Enron Corp.") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legpos, useGroups = F, main = "Позиция в компании")

Выявление значимых вершин

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

Использованные меры центральности: мощность вершин (сумма входящей и исходящей мощностей), битвинность вершин и близость вершин по Фриману.

Мощность вершин

В первую очередь проанализируем мощности вершин. Мощностью вершины в нашем случае является сумма полученных и отправленных сотрудником компании писем. Этот показатель позволит нам определить какие сотрудники являются наиболее значимыми с той точки зрения, что через них проходит большое количество информации, поступает много вопросов коллег, они осведомлены о происходящих в компании процессах и новостях. У них больше информации, значит они более значимы и могут использовать эту информацию в различных целях. Кроме того, сам факт того, что к ним часто обращаются или перед ними отчитываются или дают задания говорит о их значимости.

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

vertices$outdegree = as.data.frame(xDegreeCentrality(netmatrix))$Degree
vertices$indegree = as.data.frame(xDegreeCentrality(t(netmatrix)))$Degree
vertices$totaldegree =  vertices$indegree + vertices$outdegree

netfirst$nodes$size = vertices$totaldegree
netfirst$nodes$size = scales::rescale(netfirst$nodes$size, to = c(20, 50))

vertices %>% summarise(`Имя` = Name, `Должность` =  Note, `Позиция` = position, `Мощность` = totaldegree, `Входящая мощность` = indegree, `Исходящая мощность` = outdegree) %>% arrange(desc(`Мощность`)) %>% head(n = 20) %>% kable(align = c("l"), digits = 2, row.names = FALSE, caption = "Мощность каждой вершины графа и позиция в компании (топ 20)") 
Мощность каждой вершины графа и позиция в компании (топ 20)
Имя Должность Позиция Мощность Входящая мощность Исходящая мощность
Jeff Dasovich Employee, Government Relation Executive Low 791 174 617
Richard Shapiro Vice President, Regulatory Affairs Higher 762 480 282
Steven Kean Vice President, Vice President & Chief of Staff Higher 665 254 411
James Steffes Vice President, Government Affairs Higher 551 353 198
John Lavorato CEO, Enron America Higher 407 205 202
David Delainey CEO, Enron North America and Enron Enery Services Higher 393 166 227
NA NA NA 345 113 232
Tana Jones NA NA 343 103 240
Drew Fossum Vice President Higher 306 88 218
Shelley Corman Vice President, Regulatory Affairs Higher 259 94 165
Susan Scott NA NA 256 143 113
Mark Taylor Employee Low 242 159 83
Lindy Donoho Employee Low 228 120 108
Stephanie Panus Employee Low 227 120 107
Philip Allen Manager Middle 215 57 158
John Hodge Managing Director Middle 200 142 58
NA NA NA 196 53 143
Jeffrey Shankman President, Enron Global Mkts Higher 176 116 60
Greg Whalley President Higher 172 155 17
Mark Haedicke Managing Director, Legal Department Middle 152 109 43
visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой, где размер вершины означает её мощность") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legpos, useGroups = F, main = "Позиция в компании")

Судя по визуализации сети, можно сказать, что вершины с самой большой мощностью расположены в “сердце” графа и это как правило сотрудники высшего звена.

Выведенные в таблице результаты также показывают, что самой большой мощностью внутри сети обладают сотрудники высшего звена. Хотя важно отметить, что у некоторых сотрудников низшего и среднего звена также большая мощность (как, например, у Джеффа Дасовича), но у таких сотрудников как правило очень высокая исходящая мощность, и не очень высокая входящая. Можно предположить, что их конкретный набор задач включает осведомление сотрудников о чем-либо (как, например, Джефф Дасович является ответственным за связи с гос. органами), и они имеют высокую мощность не потому что они важная часть сети, как, например, сотрудники высшего звена, а потому что их работа - отправлять письма и отчитываться.

Битвинность вершин

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

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

При анализе мы будем уделять особое внимание не вершинам, которые находятся с самом ядре сети и имеют высокую битвинность, но вершинам, которые являются своеобразными “мостами” между ядром сети и периферией (можно предположить, что это будут сотрудники среднего звена, получающие задания от руководства и распределяющие между сотрудниками низшего звена).

Ниже представлена сеть, размер вершины в которой соответствует битвинности, а также таблица для 20 вершин с самой высокой битвинностью.

vertices$betw = as.data.frame(xBetweennessCentrality(netmatrix))$Betweenness 

vertices %>% summarise(`Имя` = Name,`Должность` =  Note,`Позиция` = position, `Битвинность` = round(betw, 2)) %>% arrange(desc(`Битвинность`))  %>% head(n = 20) %>% kable(align = c("l"), digits = 2, row.names = FALSE, caption = "Битвинность каждой вершины графа и позиция в компании (топ 20)")
Битвинность каждой вершины графа и позиция в компании (топ 20)
Имя Должность Позиция Битвинность
Philip Allen Manager Middle 1765.73
Steven Kean Vice President, Vice President & Chief of Staff Higher 1647.96
Shelley Corman Vice President, Regulatory Affairs Higher 1459.48
David Delainey CEO, Enron North America and Enron Enery Services Higher 1185.94
Susan Scott NA NA 1140.33
Richard Shapiro Vice President, Regulatory Affairs Higher 1068.79
Mark Taylor Employee Low 961.27
Dan Hyvl Employee Low 948.04
Jeff Dasovich Employee, Government Relation Executive Low 946.70
John Hodge Managing Director Middle 837.81
Andrea Ring NA NA 774.19
Jane Tholt Vice President Higher 757.19
Errol McLaughlin Employee Low 586.23
John Lavorato CEO, Enron America Higher 542.02
Mark Haedicke Managing Director, Legal Department Middle 468.51
Richard Sanders Vice President, Enron WholeSale Services Higher 455.79
Matthew Lenhart Employee Low 448.50
Robert Badeer Director Middle 380.00
Vince Kaminski Manager, Risk Management Head Middle 343.50
Jay Reitmeyer Employee Low 333.00
netfirst$nodes$size = vertices$betw
netfirst$nodes$size = scales::rescale(netfirst$nodes$size, to = c(20, 50))

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой, где размер вершины означает её битвинность") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legpos, useGroups = F, main = "Позиция в компании")

По графу видно, что вершины с самой высокой битвинностью (например, Филипп Аллен или Шелли Корман) расположены очень недалеко от самого ядра, но при этом являются “мостами” в достаточно плотные части графа на периферии.

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

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

Близость вершин по Фриману

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

Чем ниже показатель близости, тем более “центральна” вершина в графе, что означает что актор может более быстро “добраться” до любого другого актора в сети. В виду того, что данные построены на основе емэйлов, а, например, не дружеских отношений, достаточно сложно уверенно говорить о том, что в нашем случае близость вершины может действительно показать насколько сложно одному актору “добраться” до другого (потому что потенциально каждый может каждому отправить письмо без особых проблем). Но в то же время этот показатель может быть нам полезен тем, что сможет отразить насколько фактически та или иная вершина является удаленной от других, насколько часто взаимодействует с другими неудаленными вершинами, i.e. насколько центральна та или иная вершина для сети, а центральные вершины более значимы и имеют большие возможности.

Ниже представлена сеть, размер вершины в которой соответствует близости (удаленные от центра вершины более крупные), а также таблица для 20 вершин с самой низкой близостью.

vertices$closeness = as.data.frame(xClosenessCentrality(netmatrix))$FreemanCloseness

vertices %>% summarise(`Имя` = Name, `Должность` =  Note, `Позиция` = position,`Близость` = round(closeness, 2)) %>% arrange(`Близость`) %>% head(n = 20) %>% kable(align = c("l"), digits = 2, row.names = FALSE, caption = "Близость каждой вершины графа и позиция в компании (топ 20)") 
Близость каждой вершины графа и позиция в компании (топ 20)
Имя Должность Позиция Близость
Richard Shapiro Vice President, Regulatory Affairs Higher 501
Jeff Dasovich Employee, Government Relation Executive Low 512
Philip Allen Manager Middle 524
David Delainey CEO, Enron North America and Enron Enery Services Higher 526
Steven Kean Vice President, Vice President & Chief of Staff Higher 533
James Steffes Vice President, Government Affairs Higher 548
John Hodge Managing Director Middle 551
NA NA NA 561
John Lavorato CEO, Enron America Higher 564
Jeffrey Shankman President, Enron Global Mkts Higher 570
Michael Grigsby Manager Middle 570
Mark Taylor Employee Low 571
NA NA NA 573
Dan Hyvl Employee Low 575
Mark Haedicke Managing Director, Legal Department Middle 575
Richard Sanders Vice President, Enron WholeSale Services Higher 575
John Arnold Vice President Higher 577
Barry Tycholiz Vice President Higher 583
Sally Beck Employee, Chief Operating Officer Low 585
Shelley Corman Vice President, Regulatory Affairs Higher 586
netfirst$nodes$size = vertices$closeness
netfirst$nodes$size = scales::rescale(netfirst$nodes$size, to = c(20, 50))

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой, где размер вершины означает её близость") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legpos, useGroups = F, main = "Позиция в компании")

Легко заметить, что в самом центре графа расположены самые маленькие по размеру вершины с самой низкой близостью. Судя по таблице и по графу это чаще всего сотрудники высшего эшелона. Как мы видим, чем выше позиция сотрудника в иерархии компании, тем он центральней и тем проще ему или ей “добраться” до того или иного сотрудника (с важной поправкой на то, что близость рассчитывается геодезически, тогда как в реальной жизни мы часто не знаем о кратчайшем пути, чтобы добраться до того или иного сотрудника), чтобы получить или передать информацию, приказ или просьбу. Это показывает, что сотрудники более высокого положения в этом плане часто имеют преимущество.

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

Выявление сообществ

Теперь перейдём к выявлению сообществ внутри сети.

Использованные меры выделения сообществ: методом битвинности рёбер, методом Лувен

Метод битвинности рёбер

Метод битвинности рёбер предполагает разбиение сети на такие сообщества, которые ограничены рёбрами с высокой битвинностью. Т.е. некоторые ребра являются “мостами” для обособленной группы вершин, и поиск таких рёбер и групп вершин позволяет выявить сообщества. Данный метод будет использован, так как он один из очень немногих, которые подходят для ориентированной сети.

Таким образом получается выявить 44 сообщества, с модулярностью равной ~ 0.6. Ниже представлен граф с разбиением на сообщества данным методом (позиция в компании обозначена формой вершины; один цвет - одно сообщество, но представлено цветом только 12 самых крупных сообществ, размер вершин соответствует их мощности).

#0.6

vertices$cluster = membership(cluster_edge_betweenness(net))
vertices$cluster = as.factor(vertices$cluster)

netfirst$nodes$color = RColorBrewer::brewer.pal(12, "Paired")[vertices$cluster]
netfirst$nodes$shape = c("circle", "triangle", "square", "star")[vertices$position]

netfirst$nodes$size = vertices$totaldegree
netfirst$nodes$size = scales::rescale(netfirst$nodes$size, to = c(20, 50))

legshape = data.frame(label = c("Low", "Middle", "Higher", "NA"), shape = c("circle", "triangle", "square", "star"), icon.size = c(25,25,25,25))

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой, где цвет вершины означает её сообщество") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legshape, useGroups = F, main = "Позиция в компании")

Можно говорить о том, что данный метод выделяет очень много сообществ, и не позволяет нам провести дальнейший анализ, поэтому далее мы попробуем разделить сети на сообщества методом Лувена.

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

Метод Лувена

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

После разбиения методом Лувена было получено 11 сообществ, модулярность ~ 0.66, сообщества представлены на сети ниже (позиция в компании обозначена формой вершины; один цвет - одно сообщество, размер вершин соответствует их мощности).

#0.66
set.seed(2222)
vertices$louvain = as.factor(xLouvainMethod(netmatrix))
netfirst$nodes$color = RColorBrewer::brewer.pal(12, "Paired")[vertices$louvain]
netfirst$nodes$shape = c("circle", "triangle", "square", "star")[vertices$position]

legshape = data.frame(label = c("Low", "Middle", "Higher", "NA"), shape = c("circle", "triangle", "square", "star"), icon.size = c(25,25,25,25))

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой, где цвет вершины означает её сообщество") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legshape, useGroups = F, main = "Позиция в компании")

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

Исследовательские вопросы

Теперь перейдем к исследовательским вопросам, ответы на которые мы считаем важным узнать.

Вопрос 1: сотрудники с более высокой позицией будут иметь более выгодное положение в сети

Мы предполагаем, что иерархичная структура компании будет создавать такие ситуации, при которые сотрудники с более высокой позицией будут иметь больший вес внутри сети (получать больше информации, рассылать больше информации и указаний и т.д.).

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

Проведем тест ANOVA для суммарной мощности вершин сотрудников в зависимости от их положения в компании.

Так как меры центральности вершин практически всегда распределены ненормально будем использовать в расчетах логарифм мощности вершин.

ggplot(vertices) + geom_density(aes(x = log(vertices$totaldegree), group = position, fill = position), alpha = 0.5) + labs(title = "Распределение логарифма мощности в зависимости \nот позиции в компании", x = "Логарифм мощности вершины", y = "Плотность распределения", fill = "Позиция")

describeBy(log(vertices$totaldegree), vertices$position, mat = TRUE) %>% 
  select(Education = group1, N = n, Mean = mean, SD = sd, Median = median, Min = min, Max = max, 
         Skew = skew, Kurtosis = kurtosis, st.error = se) %>% 
  kable(align = c("lrrrrrrrrr"), digits = 2, row.names = FALSE, caption = "Позиция в компании и мощность вершин")
Позиция в компании и мощность вершин
Education N Mean SD Median Min Max Skew Kurtosis st.error
Low 38 3.70 1.17 3.93 1.39 6.67 0.11 -0.42 0.19
Middle 22 3.17 1.43 3.07 0.69 5.37 0.02 -1.35 0.31
Higher 26 4.37 1.46 4.47 1.39 6.64 -0.34 -0.77 0.29
NA 31 3.33 1.37 3.40 1.10 5.84 0.14 -1.06 0.25
vertices$logdegree = log(vertices$totaldegree)

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

paste("Тест на равенство дисперсий")
## [1] "Тест на равенство дисперсий"
levene_test(vertices, log(totaldegree) ~ position)
## # A tibble: 1 × 4
##     df1   df2 statistic     p
##   <int> <int>     <dbl> <dbl>
## 1     3   113     0.755 0.522
paste("Непараметрический тест")
## [1] "Непараметрический тест"
kruskal.test(vertices$logdegree, vertices$position, data = vertices, var.equal = T)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  vertices$logdegree and vertices$position
## Kruskal-Wallis chi-squared = 10.079, df = 3, p-value = 0.0179
paste("Post-hoc тест")
## [1] "Post-hoc тест"
DunnTest(logdegree ~ position, data = vertices, var.equal = T)
## 
##  Dunn's test of multiple comparisons using rank sums : holm  
## 
##               mean.rank.diff   pval    
## Middle-Low        -11.153110 0.6588    
## Higher-Low         15.672065 0.2777    
## NA-Low             -9.152377 0.6588    
## Higher-Middle      26.825175 0.0355 *  
## NA-Middle           2.000733 0.8324    
## NA-Higher         -24.824442 0.0355 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

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

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

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

Вопрос 2: менеджеры и другие сотрудники “среднего звена” будут выступать своеобразными “мостами” поставки информации

Для ответа на этот исследовательский вопрос проведем аналогичные тесты, но при этом будем проводить тест не для мощности, а для битвинности (так как битвинность поможет нам показать в какой степени тот или иной сотрудник является “мостом” между разными группами). Будем предполагать, что у менеджеров среднего звена битвинность будет выше, чем у других категорий работников.

Аналогично предыдущему исследовательскому вопросу:

ggplot(vertices) + geom_density(aes(x = log(vertices$betw + 0.1), group = position, fill = position), alpha = 0.5) + labs(title = "Распределение логарифма битвинности в зависимости \nот позиции в компании", x = "Логарифм битвинности вершины", y = "Плотность распределения", fill = "Позиция")

describeBy(log(vertices$betw + 0.1), vertices$position, mat = TRUE) %>% 
  select(Education = group1, N = n, Mean = mean, SD = sd, Median = median, Min = min, Max = max, 
         Skew = skew, Kurtosis = kurtosis, st.error = se) %>% 
  kable(align = c("lrrrrrrrrr"), digits = 2, row.names = FALSE, caption = "Позиция в компании и битвинность вершин")
Позиция в компании и битвинность вершин
Education N Mean SD Median Min Max Skew Kurtosis st.error
Low 38 1.56 3.84 1.73 -2.3 6.87 0.13 -1.84 0.62
Middle 22 1.03 3.98 -2.30 -2.3 7.48 0.40 -1.77 0.85
Higher 26 3.48 3.71 5.31 -2.3 7.41 -0.77 -1.19 0.73
NA 31 1.25 3.61 2.34 -2.3 7.04 0.12 -1.83 0.65

Мы видим, что данные по категория распределены не нормально, поэтому как и в предыдкщий раз будем проводить непараметрический тест.

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

vertices$logbetw = log(vertices$betw + 0.1)

paste("Проверка равенства дисперсий")
## [1] "Проверка равенства дисперсий"
vertices %>% levene_test(log(betw + 0.1) ~ position)
## # A tibble: 1 × 4
##     df1   df2 statistic     p
##   <int> <int>     <dbl> <dbl>
## 1     3   113     0.625 0.600
paste("Непараметрический тест")
## [1] "Непараметрический тест"
kruskal.test(vertices$logbetw, vertices$position, data = vertices, var.equal = T)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  vertices$logbetw and vertices$position
## Kruskal-Wallis chi-squared = 6.9365, df = 3, p-value = 0.07395

Как видно из результатов теста, p-value > 5%, поэтому мы вынуждены отвергнуть нашу гипотезу, ни у одной группы сотрудников по позиции нет статистически значимых отличий в битвинности по сравнению с другой. Возможно, только определенные сотрудники выступают своебразными “информационными мостами”, и эта роль не зависит от позиции сотрудника в компании.

Вопрос 3: сотрудники с разной позицией внутри компании будут общаться с сотрудниками разных позиций внутри компании, что будет отражать иерархическую структуру взаимодействия

Далее, мы хотим узнать каким сотрудникам наши акторы чаще отправляют письма: равным им по позиции или неравным? Ответ на этот вопрос поможет нам лучше понять характер взаимодействия сотрудников в компании: если сотрудники чаще отправляют письма “неравным” им (руководителям или подчиненным), то общение электронными письмами происходит в первую очередь иерархично, если же чаще сотрудники отправляют письма равным им по позиции, то общение происходит скорее горизонтально (внутри департамента или отдела). Мы предполагаем, что (судя по достаточно иерархичному строению сети с явным центром и перифериями) сотрудники чаще отправляют письма неравным им по позиции коллегам.

Тогда проверим наше предположение с помощью коэффициента ассортативности (и будем ожидать, что он будет отрицательным, так как сотрудники чаще отправляют письма неравным им по статусу и налюдается гетерофилия).

V(net)$position = vertices$position
assort_real = assortativity_nominal(net, types = V(net)$position , directed = T)

paste("Коэффициент ассортативности равен", round(assort_real, 4))
## [1] "Коэффициент ассортативности равен 0.1593"

Так как коэффициент ассортативности положительный, мы скорее всего наблюдаем гомофилию низкой/умеренной степени (так как коэфф. ассортативности соответстует коэфф. корреляции Пирсона), но чтобы быть уверенными в нашей находке далее следует посмотреть статистически значима ли она.

Ниже представлен график случайного распределения ассортативности (вне зависимости от позиции сотрудника), красные линии обозначают 0.05 и 0.95 квантили, а черная линия - наша полученная ассортативность.

number_of_permutations = 10000
assortativity_shuffled  <- rep(NA, number_of_permutations)
for(i in 1:number_of_permutations){
  V(net)$attr_shuffled = sample(V(net)$position, replace = F)
  assortativity_shuffled[i] = assortativity_nominal(net,as.factor(V(net)$attr_shuffled), directed = T)
}

quant <- quantile(assortativity_shuffled, c(0.05, 0.95)) 
df <- data.frame(assortativity_shuffled = assortativity_shuffled) 
ggplot(df) +
  geom_density(aes(assortativity_shuffled), fill="lightblue") + 
  geom_vline(xintercept=assort_real, color="black")+ 
  geom_vline(xintercept=quant[1], color="red") +
  geom_vline(xintercept=quant[2], color="red") + theme_bw() + labs(title = "График распределения случайной ассоративности,\nквантили и наша полученная ассортативность", x = "Случайная ассортативность", y = "Плотность распределения")

pvalue = sum(assortativity_shuffled >= assort_real) / number_of_permutations
paste("Тогда по нашим подсчетам p-value равно", pvalue) 
## [1] "Тогда по нашим подсчетам p-value равно 0.0048"

По графику видно, что полученный нами результат статистически значим, что подтверждается расчетом p-value.

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

Место сотрудника в сети

Теперь перейдём к описанию места конкретного сотрудника в сети. Мы рассмотрим следующего сотрудника:

hw_net_get_vertex(net, login = "debaranov_1")
## [1] "Lindy Donoho"

Она является рядовым сотрудником компании (employee), её место в сети показано на графе ниже (выделена тёмно-синим):

netfirst$nodes$shape = rep("circle")

alpha = ifelse(netfirst$nodes$Name == "Lindy Donoho", netfirst$nodes$alpha <- 2, netfirst$nodes$alpha <- 1)

alpha = as.factor(alpha)

netfirst$nodes$color = RColorBrewer::brewer.pal(12, "Paired")[alpha]

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой в Enron Corp.") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visNodes(aes(alpha = alpha))

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

Таблица ниже отражает важные характеристики, которыми обладает Линди внутри сети:

l = vertices %>% filter(Name == "Lindy Donoho") %>% summarise(`Имя` = Name, `Должность` = Note, `Позиция` = position, `Входящая мощность` = indegree, `Исходящая мощность` = outdegree, `Близость` = closeness, `Битвинность` = betw, `Сообщество по Лувену` = louvain) %>% kable(align = c("l"), digits = 4, row.names = FALSE)
l
Имя Должность Позиция Входящая мощность Исходящая мощность Близость Битвинность Сообщество по Лувену
Lindy Donoho Employee Low 120 108 661 255.3319 7

Мы видим, что входящая и исходящая мощность нашей вершины достаточно высокие, ровно как и битвинность. Близость при этом достаточно низкая в сравнении с другими вершинами. Мы можем сказать, что Линди занимает достаточно важную позицию в сети, судя по показателям центральностей. Так что несмотря на достаточно низкий статус сотрудника внутри сети (employee), Линди остаётся достаточно значимой.

Чтобы проверить, действительно ли меры центральности у Линди достаточно высокие по сравнению с другими сотрудниками в сети, рассчитаем квантили по этим мерам.

vertices = vertices %>% arrange(desc(indegree)) %>% mutate(qin = seq(0,1-1/117,1/117))
vertices = vertices %>% arrange(desc(outdegree)) %>% mutate(qout = seq(0,1-1/117,1/117))
vertices = vertices %>% arrange(desc(totaldegree)) %>% mutate(qtotal = seq(0,1-1/117,1/117))
vertices = vertices %>% arrange(desc(betw)) %>% mutate(qbetw = seq(0,1-1/117,1/117))
vertices = vertices %>% arrange(closeness) %>% mutate(qcloseness = seq(0,1-1/117,1/117))

m = vertices %>% filter(Name == "Lindy Donoho") %>% summarise(`Имя` = Name,`Позиция` = position, `Входящая мощность` = indegree, `Квантиль входящей` = round(qin, 4), `Исходящая мощность` = outdegree, `Квантиль исходящей` = round(qout, 4), `Близость` = closeness, `Квантиль близости` = round(qcloseness, 4), `Битвинность` = betw, `Квантиль битвинности` = round(qbetw, 4)) %>% kable(align = c("l"), digits = 4, row.names = FALSE)
m
Имя Позиция Входящая мощность Квантиль входящей Исходящая мощность Квантиль исходящей Близость Квантиль близости Битвинность Квантиль битвинности
Lindy Donoho Low 120 0.0855 108 0.1111 661 0.4017 255.3319 0.2051

Судя по представленным в таблице квантилям мы можем сказать, что Линди действительно имеет достаточно высокие показатели мер центральности по сравнению с другими сотрудниками в сети, так, например, она входит в топ 10% по входящей мощности, топ 12% по исходящей, топ 20% по битвинности, но только в топ 40% по близости.

Теперь попробуем посмотреть на сообщество, к которому принадлежит Линди:

netfirst$nodes$color = RColorBrewer::brewer.pal(12, "Paired")[vertices$louvain]
netfirst$nodes$shape = c("circle", "triangle", "square", "star")[vertices$position]

legshape = data.frame(label = c("Low", "Middle", "Higher", "NA"), shape = c("circle", "triangle", "square", "star"), icon.size = c(25,25,25,25))

visNetwork(nodes = netfirst$nodes, edges = netfirst$edges, height = "450px", width = "650px", main = "Граф обмена эл. почтой, где цвет вершины означает её сообщество") %>% 
  visIgraphLayout(layout = "layout_with_fr", randomSeed = 2222) %>% visEdges(arrows = "to") %>% visLegend(addNodes = legshape, useGroups = F, main = "Позиция в компании")
n = vertices %>% filter(louvain == 7) %>% summarise(`Имя` = Name, `Должность` = Note, `Позиция` = position, `Входящая мощность` = indegree, `Исходящая мощность` = outdegree, `Близость` = closeness, `Битвинность` = betw, `Сообщество` = louvain) %>% kable(align = c("l"), digits = 4, row.names = FALSE)
n
Имя Должность Позиция Входящая мощность Исходящая мощность Близость Битвинность Сообщество
Shelley Corman Vice President, Regulatory Affairs Higher 94 165 586 1459.4846 7
Susan Scott NA NA 143 113 636 1140.3325 7
Drew Fossum Vice President Higher 88 218 657 94.6656 7
Lindy Donoho Employee Low 120 108 661 255.3319 7
Stanley Horton President, Enron Gas Pipeline Higher 64 16 679 206.7813 7
Lynn Blair NA NA 22 30 722 0.0000 7
Kevin Hyatt Director, Pipeline Business Middle 51 26 754 94.3333 7
Rod Hayslett Vice President, Also Chief Financial Officer and Treasurer Higher 28 68 765 248.0000 7
Michelle Lokay Employee, Administrative Asisstant Low 42 15 848 0.0000 7
Tracy Geaccone Employee Low 46 5 859 0.0000 7
Danny McCarty Vice President Higher 64 0 1508 0.0000 7
Lawrence May Director Middle 16 0 1508 0.0000 7
Kimberly Watson NA NA 8 0 1508 0.0000 7
Teb Lokey Manager, Regulatory Affairs Middle 5 0 1508 0.0000 7

Она принадлежит к первому сообществу, в этом сообществе представлены сотрудники разного уровня, как и в большинстве других. Никаких содержательных выводов об этом сообществе сделать не получится, вполне вероятно, что это могут быть сотрудники относящиеся к одному отделу.

Обобщая изученное, можно говорить о том, что Линди является достаточно важным элементом сети переписки.

Общие выводы

В данном отчете была проанализирована сеть электронной переписки в компании Enron за декабрь 2000 года: посчитаны некоторые меры центральности вершин, сеть была разбита на сообщества, выдвинуты исследовательские вопросы, на которые был получен ответ. Кроме того, было проанализировано место одного конкретного сотрудника в сети.

На основании проведенного анализа сети электронной переписки в компании Enron можно сделать следующие выводы:

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

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

  • Разбиение сети на сообщества не даёт явных результатов для дальнейшего анализа, который был бы возможен при условии существования данных об отделе или департаменте, в котором работал каждый сотрудник.

  • Выбранный для анализа сотрудник (Линди Донохо) является достаточно значимым для сети на основании сравнения его мер центральности с мерами центральности других сотрудников и исходя из положения этого сотрудника в сети (между ядром и периферией графа).