如何使用dplyr合并多个数据框?

29

我想要使用left_join函数连接多个数据帧:

dfs <- list(
  df1 = data.frame(a = 1:3, b = c("a", "b", "c")),
  df2 = data.frame(c = 4:6, b = c("a", "c", "d")),
  df3 = data.frame(d = 7:9, b = c("b", "c", "e"))
)
Reduce(left_join, dfs)
#   a b  c  d
# 1 1 a  4 NA
# 2 2 b NA  7
# 3 3 c  5  8

这是因为它们都有相同的b列,但Reduce不允许我指定可以传递给left_join的其他参数。是否有什么解决方法可以解决这个问题?

dfs <- list(
  df1 = data.frame(a = 1:3, b = c("a", "b", "c")),
  df2 = data.frame(c = 4:6, d = c("a", "c", "d")),
  df3 = data.frame(d = 7:9, b = c("b", "c", "e"))
)

更新

这种方法可以使用:Reduce(function(...) left_join(..., by = c("b" = "d")), dfs),但是当by的元素超过一个时,会出现以下错误:Error: cannot join on columns 'b' x 'd': index out of bounds


4
你可以使用 Reduce(function(...) left_join(..., other args here), dfs) 吗? - Rich Scriven
我没有想到那个。是的,我可以!请随意将其写为您的答案。 - nachocab
哦,实际上,如果“by”有多个元素,这会出错。请参见更新。 - nachocab
3
您希望函数如何知道要连接哪些列?这不是 *_join 函数的设计目的。如果所有列都有共同的ID列,那么您的更新就可以解决问题。否则,您将需要手动指定每个配对要使用哪些列进行连接。 - Bishops_Guest
尝试使用purrr:reduce()代替? - crazyhottommy
3个回答

11

我知道已经晚了……今天我被介绍到了未回答的问题部分。抱歉打扰。

使用left_join()

dfs <- list(
              df1 = data.frame(b = c("a", "b", "c"), a = 1:3),
              df2 = data.frame(d = c("a", "c", "d"), c = 4:6),
              df3 = data.frame(b = c("b", "c", "e"), d = 7:9)
         )

func <- function(...){
  df1 = list(...)[[1]]
  df2 = list(...)[[2]]
  col1 = colnames(df1)[1]
  col2 = colnames(df2)[1]
  xxx = left_join(..., by = setNames(col2,col1))
  return(xxx)
}
Reduce( func, dfs)
#  b a  c  d
#1 a 1  4 NA
#2 b 2 NA  7
#3 c 3  5  8

使用merge()

func <- function(...){
  df1 = list(...)[[1]]
  df2 = list(...)[[2]]
  col1 = colnames(df1)[1]
  col2 = colnames(df2)[1]
  xxx=merge(..., by.x = col1, by.y = col2, , all.x = T)
  return(xxx)
}

Reduce( func, dfs)
#  b a  c  d
#1 a 1  4 NA
#2 b 2 NA  7
#3 c 3  5  8

只是需要注意的是:我必须将“key”变量保留为第一列,因为在合并后它们会自动成为数据框的第一列。 - joel.wilson

9
这对您有用吗?
jnd.tbl <- df1 %>%
    left_join(df2, by='b') %>%
    left_join(df3, by='d')

5
不太泛化(似乎这是问题的重点)。 - Gregor Thomas
1
这似乎是最好的解决方案。实际上,它具有相当好的普适性:如果您想要连接另一个表,只需在管道中添加一行即可。代码最终看起来与SQL多重连接查询并没有太大的区别。 - Hong Ooi
@HongOoi 但是by=变量是会变化的,对吗?请检查一下我的回答。 - joel.wilson

5
另一个解决方案:
library(purrr)
library(dplyr)

dfs = list(
  df1 = data.frame(a = 1:3, b = c("a", "b", "c")),
  df2 = data.frame(c = 4:6, b = c("a", "c", "d")),
  df3 = data.frame(d = 7:9, b = c("b", "c", "e"))
)

purrr::reduce(dfs, dplyr::left_join, by = 'b')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接