给定两个数据帧:

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样式)连接?也就是说,我如何获得:

df1和df2的内部连接:仅返回左表在右表中具有匹配键的行。df1和df2的外部连接:返回两个表中的所有行,连接左侧表中具有匹配键的记录。df1和df2的左外联接(或简单的左联接)返回左表中的所有行,以及右表中具有匹配键的所有行。df1和df2的右外部连接返回右表中的所有行,以及左表中具有匹配键的所有行。


额外学分:

如何执行SQL样式的选择语句?


当前回答

内部连接有data.table方法,它非常节省时间和内存(对于一些更大的data.frames也是必要的):

library(data.table)
  
dt1 <- data.table(df1, key = "CustomerId") 
dt2 <- data.table(df2, key = "CustomerId")

joined.dt1.dt.2 <- dt1[dt2]

merge也适用于data.tables(因为它是通用的并调用merge.data.table)

merge(dt1, dt2)

stackoverflow上记录的data.table:如何执行data.table合并操作将外键上的SQL联接转换为R data.table语法合并更大数据的有效替代方案。帧R如何在R中与data.table进行基本的左外连接?

另一个选项是plyr包中的join函数。【2022年注意:plyr现已退役,并已被dplyr取代。dplyr中的连接操作在本答案中描述。】

library(plyr)

join(df1, df2,
     type = "inner")

#   CustomerId Product   State
# 1          2 Toaster Alabama
# 2          4   Radio Alabama
# 3          6   Radio    Ohio

类型选项:内部、左侧、右侧、完整。

从…起join:与merge不同,[join]保留x的顺序,无论使用何种连接类型。

其他回答

dplyr从0.4开始实现了包括outer_join在内的所有连接,但值得注意的是,在0.4之前的前几个版本中,因此,在之后的相当长一段时间里,有很多非常糟糕的黑客解决方法用户代码(你仍然可以在那个时期的SO、Kaggle answers和github中找到这样的代码。因此,这个答案仍然有用。)

加入相关发布亮点:

版本0.5(2016年6月)

POSIXct类型、时区、重复项、不同因素级别的处理。更好的错误和警告。新后缀参数,用于控制重复变量名称接收的后缀(#1296)

版本0.4.0(2015年1月)

实施右联接和外联接(#96)可变联接,它从另一个表中的匹配行向一个表添加新变量。过滤联接,根据观察值是否与另一个表中的观察值匹配来过滤一个表的观察值。

版本0.3(2014年10月)

现在可以通过每个表中的不同变量进行left_join:df1%>%left_join(df2,c(“var1”=“var2”))

0.2版(2014年5月)

*_join()不再重新排序列名(#324)

版本0.1.3(2014年4月)

具有inner_join、left_join、semi_join、anti_joinouter_join尚未实现,回退是使用base::merge()(或plyr::join())尚未实现right_join和outer_join哈德利在这里提到了其他优势目前,dplyr所没有的一个小特性是,可以像Python panda那样,通过.x和.y列进行分隔。

根据哈德利在该问题中的评论采取的解决方法:

就行而言,rightjoin(x,y)与leftjoin(y,x)相同,只是列的顺序不同。轻松使用select(new_column_order)outer_join基本上是并集(leftjoin(x,y),rightjoin(y,x)),即保留两个数据帧中的所有行。

使用merge函数,我们可以选择左表或右表的变量,就像我们熟悉的SQL中的select语句一样(例如:从…中选择a.*…或选择b.*)我们必须添加额外的代码,这些代码将从新连接的表中子集。SQL:-从df1中选择a.*a内部联接df2 b,位于a.CustomerId=b.CustomerIdR:-mmerge(df1,df2,按.x=“CustomerId”,按.y=“CustomerId)[,名称(df1)]

同样的方式

SQL:-从df1中选择b.*a内部联接df2 b,位于a.CustomerId=b.CustomerIdR:-mmerge(df1,df2,by.x=“CustomerId”,by.y=“客户ID”)[,名称(df2)]

对于所有列上的内部联接,还可以使用data.table-package中的finteract或dplyr包中的intersect作为合并的替代方法,而不指定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)

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

正在修改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添加到purchases表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从customer表中选择第一个匹配行。


更新具有多个列的联接。当我们只加入一列并且对第一场比赛感到满意时,上面的方法效果很好。假设我们希望客户表中的测量年份与销售年份相匹配。

正如@bgoldst的回答所提到的,在这种情况下,匹配交互可能是一种选择。更直接地说,可以使用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常见问题解答。

在R Wiki上有一些很好的例子。我会在这里偷一对:

合并方法

由于键的名称相同,所以进行内部连接的简单方法是merge():

merge(df1, df2)

可以使用“all”关键字创建完整的内部联接(两个表中的所有记录):

merge(df1, df2, all=TRUE)

df1和df2的左外连接:

merge(df1, df2, all.x=TRUE)

df1和df2的右外连接:

merge(df1, df2, all.y=TRUE)

你可以翻转它们,拍打它们,然后摩擦它们,以获得你询问的其他两个外部连接:)

下标方法

使用下标方法与左边的df1进行左外部连接将是:

df1[,"State"]<-df2[df1[ ,"Product"], "State"]

另一种外部联接的组合可以通过对左外部联接下标示例进行排序来创建。(是的,我知道这相当于说“我会把它作为练习留给读者……”)