识别数据框A中未包含的数据框中的记录

时间:2011-10-11 15:23:14

标签: r join merge match dataframe

这是我第一次在这里发帖,所以请善待; - )

修改 在我有机会向我建议更改之前,我的问题已经结束。所以我现在正努力做得更好,感谢迄今为止回答的所有人!

问题

如何根据可用的所有属性识别数据框x.1的数据框x.2中的记录/行(即最有效方式的所有列?

示例数据

> x.1 <- data.frame(a=c(1,2,3,4,5), b=c(1,2,3,4,5))
> x.1
  a b
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5

> x.2 <- data.frame(a=c(1,1,2,3,4), b=c(1,1,99,3,4))
> x.2
  a  b
1 1  1
2 1  1
3 2 99
4 3  3
5 4  4

期望的结果

  a b
2 2 2
5 5 5

最佳解决方案

Brian Ripley教授和Gabor Grothendieck教授

> fun.12 <- function(x.1,x.2,...){
+     x.1p <- do.call("paste", x.1)
+     x.2p <- do.call("paste", x.2)
+     x.1[! x.1p %in% x.2p, ]
+ }
> fun.12(x.1,x.2)
  a b
2 2 2
5 5 5
> sol.12 <- microbenchmark(fun.12(x.1,x.2))
> sol.12 <- median(sol.12$time)/1000000000
> sol.12
> [1] 0.000207784

我的blog

最终编辑2011-10-14

这是包含在函数'mergeX()'中的最佳解决方案:

setGeneric(
    name="mergeX",
    signature=c("src.1", "src.2"),
    def=function(
        src.1,
        src.2,
        ...
    ){
    standardGeneric("mergeX")    
    }
)

setMethod(
    f="mergeX", 
    signature=signature(src.1="data.frame", src.2="data.frame"), 
    definition=function(
        src.1,
        src.2,
        do.inverse=FALSE,
        ...
    ){
    if(!do.inverse){
        out <- merge(x=src.1, y=src.2, ...)
    } else {
        if("by.y" %in% names(list(...))){
            src.2.0 <- src.2
            src.2 <- src.1
            src.1 <- src.2.0
        }
        src.1p <- do.call("paste", src.1)
        src.2p <- do.call("paste", src.2)
        out <- src.1[! src.1p %in% src.2p, ]
    }
    return(out)    
    }
)

2 个答案:

答案 0 :(得分:11)

以下是一些方法。 #1和#4假设x.1的行是唯一的。 (如果x.1的行不唯一,那么它们将仅返回重复行中的一个重复项。)其他行返回所有重复项:

# 1
x.1[!duplicated(rbind(x.2, x.1))[-(1:nrow(x.2))],]

# 2
do.call("rbind", setdiff(split(x.1, rownames(x.1)), split(x.2, rownames(x.2))))

# 3
x.1p <- do.call("paste", x.1)
x.2p <- do.call("paste", x.2)
x.1[! x.1p %in% x.2p, ]

# 4
library(sqldf)
sqldf("select * from `x.1` except select * from `x.2`")

编辑:x.1和x.2被交换,这已得到修复。在开始时也有关于限制的更正说明。

答案 1 :(得分:4)

如何使用merge - 最简单的解决方案 - 我认为它也是最快的。

tmp = merge(x.1, cbind(x.2, myid = 1:nrow(x.2)), all.x = TRUE)
    # provided that there's no column myid in both dataframes
tmp[is.na(tmp$myid), 1:ncol(x.1)] # the result

对应于:

select x1.* 
from x1 natural left join x2 
where x2.myid is NULL

(你也可以使用sqldf来做到这一点。)

请注意,添加了列myid以确保某些列没有NA值。如果您确定某些列不包含NULL值,则可以简化解决方案:

tmp = merge(x.1, x.2, all.x = TRUE)
    # provided that there's no column myid in both dataframes
tmp[is.na(tmp$some_column), 1:ncol(x.1)] # the result