如何合并数据框 (内部、外部、左、右)?

1535

给定两个数据框:

df1 = data.frame(CustomerId = c(1:6), Product = c(rep("Toaster", 3), rep("Radio", 3)))
df2 = data.frame(CustomerId = c(2, 4, 6), State = c(rep("Alabama", 2), rep("Ohio", 1)))

df1
#  CustomerId Product
#           1 Toaster
#           2 Toaster
#           3 Toaster
#           4   Radio
#           5   Radio
#           6   Radio

df2
#  CustomerId   State
#           2 Alabama
#           4 Alabama
#           6    Ohio

我如何使用数据库风格,即sql样式,连接?也就是说,我该如何做到:

  • df1df2内部连接
    仅返回左表中在右表中具有匹配键的行。
  • df1df2外部连接
    返回两个表中的所有行,以及左表中具有匹配键的连接记录。
  • df1df2左外连接(或简称左连接)
    返回左表中的所有行和右表中与之匹配的任何行。
  • df1df2右外连接
    返回右表中的所有行和左表中与之匹配的任何行。

额外加分:

我如何执行类似SQL的选择语句?


2
由RStudio创建和维护的dplyr数据转换备忘单还具有关于dplyr中连接操作的漂亮信息图表。https://www.rstudio.com/resources/cheatsheets/ - Arthur Yip
5
如果你来到这里是想了解如何合并 pandas 数据框的话,可以在这里找到相关资源:https://dev59.com/sFQJ5IYBdhLWcg3wiWab。 - cs95
1
对于@isomorphismes的链接,这里是当前的存档版本:https://web.archive.org/web/20190312112515/http://stat545.com/bit001_dplyr-cheatsheet.html - QHarr
1
在R中,左连接(Left join)、右连接(Right join)和内连接(inner join)的解释在以下链接中清楚地说明了:https://www.datasciencemadesimple.com/join-in-r-merge-in-r/ - karaimadai
14个回答

12
  1. 使用merge函数,我们可以像在SQL中使用select语句一样选择左表或右表的变量(例如:Select a.* ...or Select b.* from .....)
  2. 我们需要添加额外的代码,该代码将从新连接的表中进行子集筛选。

    • SQL :- select a.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId

    • R :- merge(df1, df2, by.x = "CustomerId", by.y = "CustomerId")[,names(df1)]

同样的方式

  • SQL :- select b.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId

  • R :- merge(df1, df2, by.x = "CustomerId", by.y = "CustomerId")[,names(df2)]


11

更新连接。 另一个重要的 SQL 样式连接是 "update join",其中使用另一个表更新(或创建)一个表中的列。

修改 OP 的示例表...

sales = data.frame(
  CustomerId = c(1, 1, 1, 3, 4, 6), 
  Year = 2000:2005,
  Product = c(rep("Toaster", 3), rep("Radio", 3))
)
cust = data.frame(
  CustomerId = c(1, 1, 4, 6), 
  Year = c(2001L, 2002L, 2002L, 2002L),
  State = state.name[1:4]
)

sales
# CustomerId Year Product
#          1 2000 Toaster
#          1 2001 Toaster
#          1 2002 Toaster
#          3 2003   Radio
#          4 2004   Radio
#          6 2005   Radio

cust
# CustomerId Year    State
#          1 2001  Alabama
#          1 2002   Alaska
#          4 2002  Arizona
#          6 2002 Arkansas

假设我们想要将客户的州从cust添加到购买表sales中,忽略年份列。使用基本R,我们可以识别匹配的行,然后复制值:
sales$State <- cust$State[ match(sales$CustomerId, cust$CustomerId) ]

# CustomerId Year Product    State
#          1 2000 Toaster  Alabama
#          1 2001 Toaster  Alabama
#          1 2002 Toaster  Alabama
#          3 2003   Radio     <NA>
#          4 2004   Radio  Arizona
#          6 2005   Radio Arkansas

# cleanup for the next example
sales$State <- NULL

正如这里所看到的,match 从客户表中选择第一匹配行。

使用多列更新连接。 当我们只在单个列上连接并满意于第一个匹配时,上述方法效果很好。 假设我们希望客户表中的测量年份与销售年份匹配。

如@bgoldst的答案所提到的,matchinteraction可能是此情况的选项。 更直接地,可以使用data.table:

library(data.table)
setDT(sales); setDT(cust)

sales[, State := cust[sales, on=.(CustomerId, Year), x.State]]

#    CustomerId Year Product   State
# 1:          1 2000 Toaster    <NA>
# 2:          1 2001 Toaster Alabama
# 3:          1 2002 Toaster  Alaska
# 4:          3 2003   Radio    <NA>
# 5:          4 2004   Radio    <NA>
# 6:          6 2005   Radio    <NA>

# cleanup for next example
sales[, State := NULL]

滚动更新连接。或者,我们可能希望采用上次找到客户的状态:
sales[, State := cust[sales, on=.(CustomerId, Year), roll=TRUE, x.State]]

#    CustomerId Year Product    State
# 1:          1 2000 Toaster     <NA>
# 2:          1 2001 Toaster  Alabama
# 3:          1 2002 Toaster   Alaska
# 4:          3 2003   Radio     <NA>
# 5:          4 2004   Radio  Arizona
# 6:          6 2005   Radio Arkansas

上述三个示例都集中在创建/添加新列上。有关更新/修改现有列的示例,请参见相关的R常见问题解答

11

如果要在所有列上进行内连接,您也可以使用data.table-包中的fintersectdplyr-包中的intersect作为merge的替代方法,而无需指定by列。这将给出两个数据框之间相等的行:

merge(df1, df2)
#   V1 V2
# 1  B  2
# 2  C  3

dplyr::intersect(df1, df2)
#   V1 V2
# 1  B  2
# 2  C  3

data.table::fintersect(setDT(df1), setDT(df2))
#    V1 V2
# 1:  B  2
# 2:  C  3

示例数据:

df1 <- data.frame(V1 = LETTERS[1:4], V2 = 1:4)
df2 <- data.frame(V1 = LETTERS[2:3], V2 = 2:3)

4

collapse 2.0 提供了另一个具有 join 的连接框架。它明显比其他选项更快

library(collapse)

join(
  df1, 
  df2, 
  how = c("left", "right", "inner", "full", "semi", "anti")
)

1
折叠2.0已发布至CRAN。 - undefined

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