3

我有两个行数不同但列数相同的数据框。在下面的示例中,数据帧 1 为 4 x 2,数据帧 2 为 3 x 2。我需要一个 4 x 3 逻辑矩阵,其中 TRUE 表示数据帧中的所有行都匹配。此示例有效,但运行较大的数据帧需要很长时间(我正在尝试两个大约 5,000 行的数据帧,但仍然只有两列)。有没有更有效的方法来做到这一点?

> 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

提前感谢您的帮助。

4

3 回答 3

1

我被您在 R-bloggers 上的帖子吸引到这里:http: //jason.bryer.org/posts/2013-01-24/Comparing_Two_Data_Frames.html

如果像您说的那样,您的数据没有数字向量,那么我想我可以建议一种更快的方法。它包括:

  1. 把你的两个 data.frames 变成两个整数矩阵
  2. 计算两个数据的行之间的欧几里得距离

使用您的数据的快速示例:

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

几点评论:

  1. 如果您的数据包含字符向量,则必须将它们转换为因子并确保它们共享相同的因子水平。
  2. 我使用fields包来计算欧几里得距离。它使用 Fortran 实现,据我所知,它是该任务最快的 R 包(我已经测试了很多,相信我。)
于 2013-05-05T00:14:14.160 回答
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

我觉得有必要至少提到使用==for 比较而不是all.equalor的危险identical。我假设您对数据类型足够熟悉,这不会成为问题。

于 2013-01-23T17:47:18.910 回答
0

我怀疑最佳解决方案取决于您拥有多少唯一行和总行数。

对于您博客上的示例,其中有 1000-1500 行但只有 20 个唯一值(对于您在那里设置的种子),我认为这样做更快:

  1. 将 id 分配给每个唯一的行,然后
  2. 在每个 data.frame 中看到的 id 向量上运行。

这是我得到的表现。@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 

我猜srbindmerges 会使这个解决方案在使用不同的数据时成本相对更高。

于 2013-05-05T05:38:22.417 回答