我有两个数据帧,行数不同,但列数相同。在下面的示例中,数据帧1是4 x 2,数据帧2是3 x 2.我需要一个4 x 3逻辑矩阵,其中TRUE表示数据帧中的所有行都匹配。这个例子有效,但是需要很长时间才能运行更大的数据帧(我正在尝试两个数据帧,大约有5000行,但仍然只有两列)。有没有更有效的方法呢?
> df1 <- data.frame(row.names=1:4, var1=c(TRUE, TRUE, FALSE, FALSE), var2=c(1,2,3,4))
> df2 <- data.frame(row.names=5:7, var1=c(FALSE, TRUE, FALSE), var2=c(5,2,3))
>
> m1 <- t(as.matrix(df1))
> m2 <- as.matrix(df2)
>
> apply(m2, 1, FUN=function(x) { apply(m1, 2, FUN=function(y) { all(x==y) } ) })
5 6 7
1 FALSE FALSE FALSE
2 FALSE TRUE FALSE
3 FALSE FALSE TRUE
4 FALSE FALSE FALSE
提前感谢您的帮助。
答案 0 :(得分:1)
我被你在R-bloggers上的帖子吸引到了:http://jason.bryer.org/posts/2013-01-24/Comparing_Two_Data_Frames.html
如果您说,您的数据没有数字向量,那么我认为我可以建议更快的方法。它包括:
使用您的数据的快速示例:
mat1 <- as.matrix(sapply(df1, as.integer))
mat2 <- as.matrix(sapply(df2, as.integer))
library(fields)
rdist(mat1, mat2) < 1e-9
# [,1] [,2] [,3]
# [1,] FALSE FALSE FALSE
# [2,] FALSE TRUE FALSE
# [3,] FALSE FALSE TRUE
# [4,] FALSE FALSE FALSE
一些评论:
fields
包来计算欧氏距离。它使用了Fortran实现,据我所知,该任务的速度最快的R包(我已经测试了很多,相信我。)答案 1 :(得分:0)
老实说,我不确定这会更快,但你可能会尝试:
foo <- Vectorize(function(x,y) {all(df1[x,] == df2[y,])})
> outer(1:4,1:3,FUN = foo)
[,1] [,2] [,3]
[1,] FALSE FALSE FALSE
[2,] FALSE TRUE FALSE
[3,] FALSE FALSE TRUE
[4,] FALSE FALSE FALSE
我觉得必须至少提到使用==
进行比较而不是all.equal
或identical
的危险。我假设你对数据类型的满意度很大,这涉及到这不会是一个问题。
答案 2 :(得分:0)
我怀疑最佳解决方案取决于您拥有的行数和总行数。
对于您博客上的示例,其中有1000-1500行,但只有20个唯一值(对于您在那里设置的种子),我认为这样做更快:
这是我得到的表现。 @ flodel的方法在我的电脑上大致相同;这是下面的第三个。免责声明:我对运行这些测试并不了解。
> set.seed(2112)
> df1 <- data.frame(row.names=1:1000,
+ var1=sample(c(TRUE,FALSE), 1000, replace=TRUE),
+ var2=sample(1:10, 1000, replace=TRUE) )
> df2 <- data.frame(row.names=1001:2500,
+ var1=sample(c(TRUE,FALSE), 1500, replace=TRUE),
+ var2=sample(1:10, 1500, replace=TRUE))
>
> # candidate method on blog
> system.time({
+ df1$var3 <- apply(df1, 1, paste, collapse='.')
+ df2$var3 <- apply(df2, 1, paste, collapse='.')
+ df6 <- sapply(df2$var3, FUN=function(x) { x == df1$var3 })
+ dimnames(df6) <- list(row.names(df1), row.names(df2))
+ })
user system elapsed
1.13 0.00 1.14
>
> rownames(df1) <- NULL # in case something weird happens to rownames on merge
> rownames(df2) <- NULL
> # id method
> system.time({
+ df12 <- unique(rbind(df1,df2))
+ df12$id <- rownames(df12)
+
+ id1 <- merge(df12,df1)$id
+ id2 <- merge(df12,df2)$id
+
+ x <- outer(id1,id2,`==`)
+ })
user system elapsed
0.11 0.02 0.13
>
> library(fields)
> # rdlist from fields method
> system.time({
+ mat1 <- as.matrix(sapply(df1, as.integer))
+ mat2 <- as.matrix(sapply(df2, as.integer))
+ rdist(mat1, mat2) < 1e-9
+ })
user system elapsed
0.15 0.00 0.16
我想rbind
和merge
会使这个解决方案在使用不同数据时成本相对较高。