从事件级数据创建网络数据

creating network data from event level data

作为网络分析的新手,我正在努力将我想要绘制的事件级数据集转换为正确的形状。我很感谢任何提示/线索/等。我到目前为止所做的,大致遵循 this 介绍。

相关数据集包含政党 Jobbik 组织的活动。每个由唯一 ID (id) 定义的事件都有关联的组织赞助商 (org_names) 及其类型 (org)。 org_1org_2org_names1org_names2 之间没有层次结构。

最初数据集采用宽格式。虽然我不确定这是否是我应该做的,但我做的第一步是将数据转换为长格式并稍微清理一下字符串。这是读取数据并将其转换为长格式的代码:

jobbik <- read.csv("http://eborbath.github.io/Whosebug/jobbik.csv")


library(tidyverse)
library(stringr)
library(igraph)

# long format

jobbik <- reshape(as.data.frame(jobbik), dir='long',
                  varying=list(c(3:13), c(14:24)),
                  v.names=c('org_names', 'org'), times = c(as.character(seq(1:11))))
jobbik$org <- str_trim(jobbik$org, side="both")
jobbik$org_names <- str_trim(jobbik$org_names, side="both")
jobbik <- jobbik %>%
  filter(!(org=="no other organizer" & org_names=="")) %>%
  filter(!(org=="JOBBIK" & org_names %in% c("Jobbik",
                                            "Jobbik Magyarországért Mozgalom",
                                            "",
                                            "JObbik",
                                            "jobbik",
                                            "aktivisté Jobbiku",
                                            "a Jobbik"))) %>% 
  mutate(org_names=ifelse(org_names=="", org, org_names)) %>%
  distinct(.)

下一步我要创建网络数据集。为此,我计算了每个独特组织参与 Jobbik 活动的次数。添加 Jobbik 作为每条边的一侧并使用 igraph 绘制数据:

network <- jobbik %>%
  select(id, org_names) %>% 
  group_by(org_names) %>%
  summarise(weight = n()) %>% 
  ungroup() %>% 
  mutate(from=1,
         org_names=as.factor(org_names)) %>% 
  mutate(org_id=as.numeric(factor(org_names)))

edges <- network %>% select(from, org_id, weight)
nodes <- network %>% select(org_id, org_names) %>% 
  mutate(org_names=as.character(org_names))


routes_igraph <- graph_from_data_frame(d = edges, vertices = nodes, directed = FALSE)

plot(routes_igraph, layout = layout_with_graphopt)

虽然这会运行并创建网络,但它只会让我了解每个独特组织与 Jobbik 之间的关系,但不会了解这些不涉及 Jobbik 的组织之间的关系。我意识到错误出在我所做的数据转换中,我应该使用事件级别信息来计算每个组织对参与组织某些事物的次数,然后绘制该数据。不幸的是,虽然我不知道如何到达那里。我很感激任何帮助。

我并不是网络分析方面的专家,igraph 尤其如此。但我认为类似的东西可能会有所帮助。

我更改了您分析的预处理部分,因为我发现在某种程度上没有什么复杂的地方:

  1. 匈牙利语编码:找到正确的编码需要时间(请参阅 read_csv 调用中的 locale = 'cp1250
  2. 收集后,我将 org_name* 更改为 org,将 org* 更改为 type;
  3. 我使用 chop 使 spread -> unnest;
  4. 更容易
  5. 我尝试缩短 filter 调用时间,但收效甚微;
  6. 我用stringr::str_to_title()来统一org var,因为有相同的名字,只是名字的第n个字大写与否;
  7. 我使用 coalesce 来填充 NAs of org var 的值来自 type var.

    library(tidyverse)
    library(magrittr)
    library(igraph)
    
    jobbik <- read_csv(
      "http://eborbath.github.io/Whosebug/jobbik.csv", 
      trim_ws = T, 
      locale = locale(encoding = 'cp1250')
      )
    
    jobbik %<>%
      gather('key', 'val', -c('id', 'date')) %>%
      mutate(
        key = case_when(
          grepl('^org_names\d+$', key) ~ 'org',
          grepl('^org\d+$',       key) ~ 'type',
          TRUE                         ~ key
        )
      ) %>%
      chop(val) %>%
      spread(key, val) %>%
      unnest(c(org, type)) %>%
      filter(
        !(is.na(org) & (type == 'no other organizer')) &
        !((is.na(org) | grepl('.*jobbik.*', org, T  )) & (type == 'JOBBIK'))
      ) %>%
      mutate(org = str_to_title(coalesce(org, type)))
    

为了形成图形边缘的数据框,我按事件的 id 分组,过滤掉所有仅由一个组织支持的事件(因此与其他组织没有联系),并且最后,我在具有 combn 功能的组织之间的 id 内创建了对。结果是字符向量 Org A-Org B,在取消嵌套之后,我使用 - 作为拆分将其分为 cols fromto(这有潜在的危险,如果名称组织的名称中有 - 符号)。我还过滤掉所有自循环(如果有的话)。最后一个操作是 count,计算每个单独对在 Jobbik 会议列表中出现的频率。我将它分配给 width 因为在绘图时,igraph::plot 会将其用作边缘的宽度。

ed <- jobbik %>%
  group_by(id) %>%
  filter(n() > 1) %>%
  summarise(edge = list(combn(org, 2, paste, collapse = '-'))) %>%
  unnest(edge) %>%
  separate(edge, into = c('from', 'to'), sep = '-') %>%
  filter(from != to) %>%
  count(from, to, name = width)

对顶点执行类似的分析。我在这里为顶点添加了额外的信息,即事件 iddate、组织 type,您可以进一步使用它,color - 映射给定组织的次数。支持 Jobbik 和后面情节的一些额外图形参数。

nd <- jobbik %>%
  filter(org %in% c(ed$from, ed$to)) %>%
  group_by(name = org) %>%
  summarise(
    id   = sprintf('Event ids: %s', paste(id, collapse = ', ')),
    date = sprintf('Event dates: %s', paste(date, collapse = ', ')),
    type = sprintf('Org. type: %s',   paste(type, collapse = '; ')),
    color = n() 
  ) %>%
  ungroup() %>%
  mutate(
    color = heat.colors(10)[cut(color, 10)],
    frame.color = NA,
    label.dist = 1,
    label.cex = .5,
    label.color = 'gray10'
  )

有了这些数据我们可以制作无向图,使用graph_from_data_frame()函数:

g <- graph_from_data_frame(ed, F, nd)
vertex_attr(g, 'size') <- degree(g, mode = 'all')

在上面的第二行中,我添加了顶点属性 size 以将顶点的度数映射到顶点的大小。

最后要规划社区,我只能做:

plot(
  g,
  edge.curved  = .2,
  layout = layout_with_kk,
  asp = 1,
  main = 'Jobbik interaction network',
  )