J'ai trois dataframes comme ci-dessous:

df3 <- data.frame(col1=c('A','C','E'),col2=c(4,8,2))
df2 <- data.frame(col1=c('A','B','C','E','I'),col2=c(4,6,8,2,9))
df1 <- data.frame(col1=c('A','D','C','E','I'),col2=c(4,7,8,2,9))

Les différences entre deux fichiers peuvent être les suivantes:

anti_join(df2, df3)
# Joining, by = c("col1", "col2")
#   col1 col2
# 1    B    6
# 2    I    9

anti_join(df3, df2)
# Joining, by = c("col1", "col2")
# [1] col1 col2
# <0 rows> (or 0-length row.names)

anti_join(df1, df2)
# Joining, by = c("col1", "col2")
#   col1 col2
# 1    D    7

anti_join(df2, df1)
# Joining, by = c("col1", "col2")
#   col1 col2
# 1    B    6

Je souhaite créer un master dataframe avec toutes les valeurs de col1 et col2 spécifiques à chaque dataframe. Si une telle valeur n'est pas présente, elle doit renseigner NA.

  col1 df1_col2 df2_col2 df3_col2
1    A        4        4        4 
2    B       NA        6       NA  
3    C        8        8        8
4    E        2        2        2 
5    I        9        9       NA
6    D        7       NA       NA

L'essence de la sortie ci-dessus pourrait être établie à partir des commandes anti_join ci-dessus. Cependant, il ne fournit pas une image complète à la fois. Des réflexions sur la façon d'y parvenir?

Modifier: Pour plusieurs valeurs dans col2 pour col1, la sortie est un peu plus compliquée. Par exemple, A a des valeurs 4, 3.

df3 <- data.frame(col1=c('A','C','E'),col2=c(4,8,2))
df2 <- data.frame(col1=c('A','A','B','C','E','I'),col2=c(4,3,6,8,2,9))
df1 <- data.frame(col1=c('A','A','D','C','E','I'),col2=c(4,3,7,8,2,9))

lst_of_frames <- list(df1 = df1, df2 = df2, df3 = df3)
lst_of_frames %>%
  imap(~ rename_at(.x, -1, function(z) paste(.y, z, sep = "_"))) %>%
  reduce(full_join, by = "col1")

Il donne la sortie ci-dessous.

#   col1 df1_col2 df2_col2 df3_col2
# 1    A        4        4        4
# 2    A        4        3        4
# 3    A        3        4        4
# 4    A        3        3        4
# 5    D        7       NA       NA
# 6    C        8        8        8
# 7    E        2        2        2
# 8    I        9        9       NA
# 9    B       NA        6       NA

La partie intéressante de la sortie est:

#   col1 df1_col2 df2_col2 df3_col2
# 1    A        4        4        4
# 2    A        4        3        4
# 3    A        3        4        4
# 4    A        3        3        4

Alors que le résultat attendu est:

#   col1 df1_col2 df2_col2 df3_col2
# 1    A        4        4        4
# 2    A        3        3       NA
1
Prradep 28 août 2020 à 19:17

2 réponses

Meilleure réponse

Similaire à la réponse de @ tamtam, mais un peu programmatique si vous avez une liste dynamique de cadres.

lst_of_frames <- list(df1 = df1, df2 = df2, df3 = df3)
# lst_of_frames <- tibble::lst(df1, df2, df3)    # thanks, @user63230
library(dplyr)
library(purrr)  # imap, reduce
lst_of_frames %>%
  imap(~ rename_at(.x, -1, function(z) paste(.y, z, sep = "_"))) %>%
  reduce(full_join, by = "col1")
#   col1 df1_col2 df2_col2 df3_col2
# 1    A        4        4        4
# 2    D        7       NA       NA
# 3    C        8        8        8
# 4    E        2        2        2
# 5    I        9        9       NA
# 6    B       NA        6       NA

Il est important (pour renommer automatiquement les colonnes) que la liste de cadres soit une liste nommée ; mon hypothèse était le nom de la variable frame list(df1=df1), mais il pourrait tout aussi bien être list(A=df1) de produire une colonne nommée A_col2 à la fin.

1
r2evans 28 août 2020 à 17:27

Vous pouvez utiliser la fonction full_join du package dplyr.

df_master <- df1 %>% 
  full_join(df2, by = "col1") %>% 
  full_join(df3, by = "col1") %>% 
  select(col1, df1_col2 = col2.x, 
         df2_col2 = col2.y,
         df3_col2 = col2)

  col1 df1_col2 df2_col2 df3_col2
1    A        4        4        4
2    D        7       NA       NA
3    C        8        8        8
4    E        2        2        2
5    I        9        9       NA
6    B       NA        6       NA
4
tamtam 28 août 2020 à 16:34