создание сетевых данных из данных уровня события - PullRequest
0 голосов
/ 19 января 2020

Как новичок ie в сетевом анализе, я борюсь с преобразованием набора данных уровня событий, который я хочу построить в правильной форме. Я благодарен за любые подсказки / приводит / et c. То, что я делал до сих пор, в целом следует этому введению.

Данный набор данных содержит события, организованные политической партией Джоббик. Каждое событие, определенное уникальным идентификатором (id), имеет связанных организационных спонсоров (org_names) и их тип (org). Не существует иерархии между org_1, org_2 или org_names1 и org_names2.

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

jobbik <- read.csv("http://eborbath.github.io/stackoverflow/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. Я понимаю, что ошибка заключается в преобразовании данных, которое я делаю, и я должен использовать информацию уровня событий, чтобы рассчитать, сколько раз каждая организационная пара участвовала в организации чего-либо вместе, а затем нанести эти данные на график. К сожалению, хотя я не знаю, как туда добраться. Я благодарен за любую помощь.

1 Ответ

1 голос
/ 19 января 2020

Я не совсем эксперт по сетевому анализу, и igraph в частности. Но я думаю, что что-то подобное может быть полезным.

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

  1. Кодировка венгерского языка: Потребовалось время, чтобы найти правильную кодировку (см. locale = 'cp1250 в read_csv вызове;
  2. После сбора я изменил org_name* на org и org* на type;
  3. Я использую chop, чтобы упростить spread -> unnest;
  4. Я пытался сделать filter вызов короче, но без особого успеха;
  5. Я использую stringr::str_to_title(), чтобы объединить org var, потому что есть такие же имена, которые отличаются только тем, что n-е слово в заглавных буквах или нет;
  6. Я использую coalesce для заполните NA s org var значениями от type var.

    library(tidyverse)
    library(magrittr)
    library(igraph)
    
    jobbik <- read_csv(
      "http://eborbath.github.io/stackoverflow/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 из событие, отфильтровывая все события, которые поддерживаются только одной организацией (поэтому нет связи с другими организациями), и, наконец, я создаю p в пределах id между организациями с функцией combn. В результате получается символьный вектор Org A-Org B, который после разнесения я разделяю на столбцы from и to, используя - в качестве разбиения (что потенциально опасно, если имя организации имеет - символ в нем). Я также отфильтровываю все самопетли, если они есть. Последняя операция - 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)

Аналогичный анализ выполняется для вершин. Я добавляю сюда дополнительную информацию для вершин, а именно: событие id, date, организацию 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',
  )

Jobbik

...