查找数据框的补充(反连接)
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.table
s 二进制连接
进行某种类型的反连接
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 包可能不太容易表达的问题很有用。
我有两个数据框(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.table
s 二进制连接
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 包可能不太容易表达的问题很有用。