Как получить список ребер (неориентированный граф) из сгруппированного фрейма данных в R?

Я создал сеть, в которой люди подключены к определенным событиям (участники события 1 подключены к узлу «event1»).

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

Я делал что-то подобное в прошлом, используя Excel для работы с необработанными данными. Я хотел бы знать, есть ли более быстрый и лучший способ сделать это, не выходя из R.

Набор данных выглядит следующим образом:

net1
from        to 
Person 1   Event1 
Person 2   Event1 
Person 3   Event2
Person 4   Event2 
Person 5   Event2 
Person 6   Event3
...

В качестве примера я хотел бы удалить «Event1» и соединить Person1 и Person2 вместе, как я это делаю.

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


person ValerManf    schedule 09.07.2019    source источник


Ответы (1)


Мы можем сделать это, используя tidyverse.

  1. group_split с аргументом keep = FALSE разбивает фрейм данных по столбцу to на список фреймов данных, удаляя переменную группировки в выводе.

  2. map_dfr расширяет каждый кадр данных, находя все комбинации from и самого себя (например, expand.grid). _dfr означает, что выходной список будет привязан к строке для формирования кадра данных.

  3. pmap_dfr работает с каждой строкой фрейма данных и сортирует по горизонтали (sort(c(...))). set_names нужен для выравнивания столбцов после сортировки. tibble(!!! объединяет отсортированный вектор в строку tibble, эффективно превращая его в вектор-строку.

  4. filter и distinct удаляют петли и повторяющиеся ссылки соответственно.

Обратите внимание, что и group_split, и group_map в настоящее время являются экспериментальными функциями. Пожалуйста, используйте с осторожностью.

library(tidyverse)

net1 %>%
  group_by(to) %>%
  group_split(keep = FALSE) %>%
  map_dfr(expand, crossing(from, to = from)) %>%
  pmap_dfr(~ tibble(!!!sort(c(...)) %>% set_names(c("from", "to")))) %>%
  filter(from != to) %>%
  distinct()

или с group_map:

net1 %>%
  group_by(temp = to) %>%
  group_map(~ expand(.x, crossing(from, to = from))) %>%
  ungroup() %>%
  select(-temp) %>%
  pmap_dfr(~ tibble(!!!sort(c(...)) %>% set_names(c("from", "to")))) %>%
  filter(from != to) %>%
  distinct()

или с inner_join:

net1 %>%
  inner_join(net1, by = "to") %>%
  select(from = from.x, to = from.y) %>%
  pmap_dfr(~ tibble(!!!sort(c(...)) %>% set_names(c("from", "to")))) %>%
  filter(from != to) %>%
  distinct()

Мы также можем использовать graph_from_data_frame вместо pmap_dfr для возврата неориентированного графа (обязательно загрузите igraph до загрузки tidyverse, иначе вы можете получить неожиданные ошибки):

library(igraph)
library(tidyverse)

net1 %>%
  inner_join(net1, by = "to") %>%
  select(from = from.x, to = from.y) %>%
  igraph::graph_from_data_frame(directed = FALSE) %>%
  igraph::as_data_frame(what = "edges") %>%
  filter(from != to) %>%
  distinct()

Вывод:

# A tibble: 4 x 2
  from     to      
  <chr>    <chr>   
1 Person_1 Person_2
2 Person_3 Person_4
3 Person_3 Person_5
4 Person_4 Person_5

Данные:

net1 <- structure(list(from = c("Person_1", "Person_2", "Person_3", "Person_4", 
"Person_5", "Person_6"), to = c("Event1", "Event1", "Event2", 
"Event2", "Event2", "Event3")), class = "data.frame", row.names = c(NA, 
-6L))
person acylam    schedule 09.07.2019
comment
Большое спасибо за понятный (даже для нуба вроде меня) и подробный ответ. inner_join и graph_from_data_frame работают отлично. К сожалению, при запуске других методов я получаю ответ: Error in crossing(from, to = from) : unused argument (to = from) На вопрос дан прекрасный ответ, так что еще раз спасибо. Однако решение этой последней проблемы может помочь другим. У вас есть идеи, почему я возвращаю эту ошибку? - person ValerManf; 11.07.2019
comment
@ValerManf Вы получите эту ошибку, если загрузите igraph после tidyverse (полагаю, из-за двух разных функций с одинаковыми именами). Если вы хотите использовать обе библиотеки, сначала загрузите igraph перед загрузкой tidyverse (перезапустите сеанс и повторите попытку, если вы уже загрузили tidyverse). - person acylam; 11.07.2019