Как объединить фреймы данных столбцом списка и столбцом, содержащим отдельные значения

#r #dplyr #tidyverse

Вопрос:

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

 df1 <- tibble(Group = c("Group_1", "Group_2", "Group_3"),
              Members = list(letters[1:3],
                             letters[4:6],
                             letters[7:12]))
df2 <- tibble(Letters = c("a","g","f","b"),
              Value = 1:4)
 

Конечный фрейм данных будет выглядеть следующим образом:

 df3 <- tibble(Letters = c("a","g","f","b"),
              Value = 1:4,
              Group = c("Group_1", "Group_3", "Group_2", "Group_1"),
              Members = list(letters[1:3],
                             letters[7:12],
                             letters[4:6],
                             letters[1:3]))
 

В идеале это можно было бы сделать с помощью dplyr или другого пакета tidyverse

Ответ №1:

Вы могли бы использовать

 library(dplyr)
library(tidyr)

df1 %>% 
  unnest(Members) %>% 
  rename(Letters = Members) %>% 
#  left_join(df2, by = "Letters") %>% 
#  drop_na() %>% 
  inner_join(df2, by = "Letters") %>% # (c) by akrun
  right_join(df1, by = "Group")
 

получить

 # A tibble: 4 x 4
  Group   Letters Value Members  
  <chr>   <chr>   <int> <list>   
1 Group_1 a           1 <chr [3]>
2 Group_1 b           4 <chr [3]>
3 Group_2 f           3 <chr [3]>
4 Group_3 g           2 <chr [6]>
 

Ответ №2:

Или с помощью base R

 cbind(df2, df1[sort(unlist(lapply(df1$Members, function(x) match(df2$Letters, x)))),])
  Letters Value   Group          Members
1       a     1 Group_1          a, b, c
2       g     2 Group_1          a, b, c
3       f     3 Group_2          d, e, f
4       b     4 Group_3 g, h, i, j, k, l
 

Ответ №3:

Альтернатива с одним соединением:

 library(tidyr)
library(dplyr)
library(purrr)

df1 %>%
  mutate(Letters = map(Members, ~ .x[.x %in% df2$Letters])) %>%
  unnest(Letters) %>%
  left_join(df2)

Joining, by = "Letters"
# A tibble: 4 x 4
  Group   Members   Letters Value
  <chr>   <list>    <chr>   <int>
1 Group_1 <chr [3]> a           1
2 Group_1 <chr [3]> b           4
3 Group_2 <chr [3]> f           3
4 Group_3 <chr [6]> g           2