将一个数据框与存储在不同列的列表中的多个数据框连接起来

M--*_*M-- 6 r dataframe dplyr purrr

我有一个数据框 ( df1) 和一个数据框列表 ( test) ,如下所示;我想加入df1每个数据帧test并填充一个新列 ( X),同时保持所有其他记录完好无损。

read.table(text = "Fruits      A    B     C     D
                   Apple       10   1.3   NA    NA
                   Orange      0.2  NA    0.21  NA
                   Grape       NA   0.06  51    0.7
                   Grape       NA   0.06  51    0.7
                   Grape       1    0.06  51    0.7
                   Grape       NA   0.06  NA    0.8
                   Berry       11   20    0.3   0.04
                   Apple       NA   1.1   0.5   NA   
                   Apple       NA   1.2   0.5   NA
                   Apple       NA   1.3   0.1   NA
                   Berry       NA   NA    0.3   0.04
                   Berry       1    NA    0.9   0.01
                   Apple       1    1.3   0.5   NA
                   Apple       1    1.3   0.5   NA", 
            stringsAsFactors = FALSE, header = TRUE) -> df1

list(data.frame(Fruits = c("Apple"), A = 10, X = "oh"),
     data.frame(Fruits = c("Berry"), A = 11, B = 20, X = "duh")) -> test
Run Code Online (Sandbox Code Playgroud)

这是预期的输出:

   Fruits    A     B     C    D    X
1   Apple 10.0  1.30    NA   NA   oh
2  Orange  0.2    NA  0.21   NA   NA   
3   Grape   NA  0.06 51.00 0.70   NA
4   Grape   NA  0.06 51.00 0.70   NA
5   Grape  1.0  0.06 51.00 0.70   NA
6   Grape   NA  0.06    NA 0.80   NA
7   Berry 11.0 20.00  0.30 0.04   duh
8   Apple   NA  1.10  0.50   NA   NA
9   Apple   NA  1.20  0.50   NA   NA
10  Apple   NA  1.30  0.10   NA   NA
11  Berry   NA    NA  0.30 0.04   NA
12  Berry  1.0    NA  0.90 0.01   NA
13  Apple  1.0  1.30  0.50   NA   NA
14  Apple  1.0  1.30  0.50   NA   NA
Run Code Online (Sandbox Code Playgroud)

简单地循环遍历其中的数据帧test是行不通的,因为它会为每个数据帧创建一个数据帧..._join,并且还会为第二次迭代创建重复的行。也许我们可以使用条件mutate

purrr::map(test, ~full_join(df1, .x))
Run Code Online (Sandbox Code Playgroud)

我很可能错过了一些简单的东西,但我不想加入full_join之后的输出,因为我的实际行df1数超过 100 万行。

zep*_*ryl 2

我会用purrr::reduce()而不是map(). 但这提出了一个问题,即在第一次迭代后,X出现在两个数据框中并被视为键。一种解决方法是为所有X列指定唯一的名称,然后在加入后合并。

library(dplyr)
library(purrr)

test2 <- imap(test, ~ rename(.x, "X{.y}" := X))

test2 %>% 
  reduce(full_join, .init = df1) %>% 
  mutate(X = coalesce(X1, X2), .keep = "unused")
Run Code Online (Sandbox Code Playgroud)
   Fruits    A     B     C    D    X
1   Apple 10.0  1.30    NA   NA   oh
2  Orange  0.2    NA  0.21   NA <NA>
3   Grape   NA  0.06 51.00 0.70 <NA>
4   Grape   NA  0.06 51.00 0.70 <NA>
5   Grape  1.0  0.06 51.00 0.70 <NA>
6   Grape   NA  0.06    NA 0.80 <NA>
7   Berry 11.0 20.00  0.30 0.04  duh
8   Apple   NA  1.10  0.50   NA <NA>
9   Apple   NA  1.20  0.50   NA <NA>
10  Apple   NA  1.30  0.10   NA <NA>
11  Berry   NA    NA  0.30 0.04 <NA>
12  Berry  1.0    NA  0.90 0.01 <NA>
13  Apple  1.0  1.30  0.50   NA <NA>
14  Apple  1.0  1.30  0.50   NA <NA>
Run Code Online (Sandbox Code Playgroud)

如果test有很多元素,列出来会很烦人coalesce(X1, X2, X3, ..., Xn)。在这种情况下,您可以使用以下替代方案:

test2 %>% 
  reduce(full_join, .init = df1) %>% 
  mutate(X = coalesce(!!!syms(paste0("X", seq_along(test2)))), .keep = "unused")
Run Code Online (Sandbox Code Playgroud)