2013-01-23 34 views
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 

在此先感谢您的帮助。

回答

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.equalidentical比较危险。我假设你很满意数据类型,这不会成为问题。

1

我在这里抽你邮递R-博客:http://jason.bryer.org/posts/2013-01-24/Comparing_Two_Data_Frames.html

如果像你说的,你的数据没有数值向量,那么我想我可以提出一个更快的方法。它由:

  1. 把你的两个data.frames成整数的两个矩阵
  2. 计算你的两个DATAS行之间的欧氏距离
使用您的数据

简单的例子:

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软件包(我已经测试了很多,相信我)。
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 

我猜rbindmerge s就使这个解决方案相对更昂贵与不同的数据。

+0

我在这里被这里所吸引,因为@ flodel在R博客上看到过你的帖子。连锁反应。 – Frank

相关问题