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

Find complement of a data frame (anti - join)

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

数据框 df:

heads
row1
row2
row3
row4
row5

数据框 df1:

heads
row3
row5

那么期望的输出df2是:

heads
row1
row2
row4

dplyr

开始尝试 anti_join
library(dplyr)
anti_join(df, df1, by='heads')

尝试 %in% 命令并使用 !

反转它
df[!df$heads %in% df1$heads,]

您还可以使用 data.tables 二进制连接

进行某种类型的反连接
library(data.table)
setkey(setDT(df), heads)[!df1]
#    heads
# 1:  row1
# 2:  row2
# 3:  row4

编辑: 开始 data.table v1.9.6+ 我们可以在不设置密钥的情况下加入 data.tables使用 on

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

EDIT2: Starting data.table v1.9.8+ fsetdiff 被引入,这基本上是上面的解决方案,就在 x data.table 的所有列名之上,例如x[!y, on = names(x)]。如果 all 设置为 FALSE(默认行为),则仅返回 x 中的唯一行。对于每个data.table中只有一列的情况,以下将等同于之前的解决方案

fsetdiff(df, df1, all = TRUE)

另一种选择,使用基数 R 和 setdiff 函数:

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

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

我发现 setdiff tahtn %in% 更具可读性,并且在我不需要时不希望需要额外的库,但是你使用哪个答案主要是个人品味的问题。

通过操作 plyr 包的 match_df 的代码创建函数 negate_match_df 的另一种选择。

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)

dplyr 也有 setdiff() 这会让你

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

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

dplyr 有很多很棒的功能:有关快速简单的指南,请参阅 here.

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

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)

sqldf 包对于那些使用 SQL 逻辑很容易表达,但使用基本 R 或其他 R 包可能不太容易表达的问题很有用。