查找数据框的补码(反连接)

Find complement of a data frame (anti - join)

提问人:oercim 提问时间:2/25/2015 最后编辑:Henrikoercim 更新时间:11/1/2018 访问量:39165

问:

我有两个数据帧(df 和 df1)。df1 是 df 的子集。我想得到一个数据帧,它是 df 中 df1 的补充,即返回第一个数据集的行,而这些行在第二个数据集中不匹配。例如,让我们,

数据帧 DF:

heads
row1
row2
row3
row4
row5

数据帧 DF1:

heads
row3
row5

则所需的输出 df2 为:

heads
row1
row2
row4
连接 合并 r-faq

评论


答:

45赞 akrun 2/25/2015 #1

尝试从anti_joindplyr

library(dplyr)
anti_join(df, df1, by='heads')
29赞 C_Z_ 2/25/2015 #2

尝试该命令并使用%in%!

df[!df$heads %in% df1$heads,]

评论

3赞 bartektartanus 6/15/2016
支持基本 R 解决方案,尽管它可能不是这里最快的解决方案。
2赞 Blind0ne 5/9/2017
如果我想做一个反连接并有多个键/列,语法是什么样的?
0赞 GKi 5/23/2019
@Blind0ne:您可以使用 或 对多个密钥进行反联接。interactionpastekey <- c("colName1", "colName2"); df[!interaction(df[key]) %in% interaction(df1[key]),]
78赞 David Arenburg 2/25/2015 #3

你也可以用s二进制连接做某种类型的反连接data.table

library(data.table)
setkey(setDT(df), heads)[!df1]
#    heads
# 1:  row1
# 2:  row2
# 3:  row4

编辑:从 data.table v1.9.6+ 开始,我们可以在使用on

setDT(df)[!df1, on = "heads"]

编辑2:引入了启动 data.table v1.9.8+,它基本上是上述解决方案的变体,只是在 data.table 的所有列名之上,例如 .如果设置为(默认行为),则仅返回 中的唯一行。对于每个 data.table 中只有一列的情况,以下解决方案将等效于前面的解决方案fsetdiffxx[!y, on = names(x)]allFALSEx

fsetdiff(df, df1, all = TRUE)

评论

0赞 Herman Toothrot 10/1/2018
我喜欢在设置键后使用 merge[df,df2]。此操作的逆义是什么?
0赞 David Arenburg 10/2/2018
@HermanToothrot 答案实际上是与你所写的相反df[!df2]
0赞 JdeMello 1/16/2019
如果中的密钥具有不同的名称怎么办?on
2赞 David Arenburg 1/16/2019
@JdeMello您可以指定不同的键 - 请参阅“参数”部分中的查找。?data.tableon
0赞 jangorecki 5/13/2020
AFAIK无济于事,它会将整行视为元素并减去重复行的数量。X=1,1,1,1;Y=1,1;然后它给出两行,因为 4-2=2。Antijoin 将给出 0。fsetdiff(all=T)
9赞 Joe 2/25/2015 #4

另一个选项,使用基本 R 和函数:setdiff

df2 <- data.frame(heads = setdiff(df$heads, df1$heads))

setdiff功能完全符合您的想象;将两个参数作为集合,并从第一个参数中删除第二个参数中的所有项。

我发现 tahtn 更具可读性,并且在我不需要它们时不想需要额外的库,但您使用哪个答案很大程度上取决于个人品味。setdiff%in%

评论

1赞 David Arenburg 2/25/2015
setdiff并且功能几乎相同。%in%
0赞 Joe 2/25/2015
@DavidArenburg同意,这就是为什么我认为这只是易读性和品味的问题。
2赞 Marat Talipov 2/25/2015
@DavidArenburg,该函数是 。match
0赞 David Arenburg 2/25/2015
@MaratTalipov我知道,这就是我的意思
3赞 user2100721 6/28/2016 #5

另一种选择是通过操作包的代码来创建函数。negate_match_dfmatch_dfplyr

library(plyr)
negate_match_df <- function (x, y, on = NULL) 
{
if (is.null(on)) {
    on <- intersect(names(x), names(y))
    message("Matching on: ", paste(on, collapse = ", "))
}
keys <- join.keys(x, y, on)
x[!keys$x %in% keys$y, , drop = FALSE]
}

数据

df <- read.table(text ="heads
row1
row2
row3
row4
row5",header=TRUE)

df1 <- read.table(text ="heads
row3
row5",header=TRUE)

输出

negate_match_df(df,df1)
6赞 leerssej 11/10/2016 #6

dplyr 也有,可以让你setdiff()

enter image description here

setdiff(bigFrame, smallFrame)获取第一个表中的额外记录。

因此,对于 OP 的示例,代码将读取setdiff(df, df1)

DPLYR 具有许多出色的功能:有关快速简易指南,请参阅此处。

评论

0赞 jangorecki 5/11/2020
它是否像反联接那样处理重复项?
1赞 Pablo Olmos de Aguilera C. 5/13/2020
在 dplyr.tidyverse.org/reference/setops.html 中,setdiff 管理重复项。
1赞 jangorecki 5/13/2020
我打开了链接,我可以看到“当心 intersect()、union() 和 setdiff() 删除重复项”
1赞 jangorecki 5/13/2020
反联接在 LHS 上保留重复的行,并忽略 RHS 上的重复行。我所说的行是指我们联接的列。
1赞 jangorecki 5/13/2020
另一方面,data.table setops 管理重复项,但它仍然不是反联接,rdatatable.gitlab.io/data.table/reference/setops.html
4赞 Tim Biegeleisen 11/1/2018 #7

答案很晚,但对于另一种选择,我们可以尝试使用以下软件包进行正式的 SQL 反连接:sqldf

library(sqldf)
sql <- "SELECT t1.heads
        FROM df t1 LEFT JOIN df1 t2
            ON t1.heads = t2.heads
        WHERE t2.heads IS NULL"
df2 <- sqldf(sql)

该包可用于那些使用 SQL 逻辑轻松表述的问题,但使用基本 R 或其他 R 包可能不太容易表述的问题。sqldf