有没有比较两个数据帧的有效方式
问题描述:
我有两个数据帧,行数不同,但列数相同。在下面的例子中,数据帧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
在此先感谢您的帮助。
答
我真的不知道这是否会更快,但你可以尝试:
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
比较危险。我假设你很满意数据类型,这不会成为问题。
答
我在这里抽你邮递R-博客:http://jason.bryer.org/posts/2013-01-24/Comparing_Two_Data_Frames.html
如果像你说的,你的数据没有数值向量,那么我想我可以提出一个更快的方法。它由:
- 把你的两个data.frames成整数的两个矩阵
- 计算你的两个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
几点意见:
- 如果您的数据包含字符向量,则必须将其转换为因子,并确保它们具有相同的因子水平。
- 我用
fields
包来计算欧几里德距离。它使用Fortran的实现,就我所知最快的R软件包(我已经测试了很多,相信我)。
答
我怀疑最佳解决方案取决于有多少独特的行和你有多少行总数。
有关你的博客,其中有1000-1500行,但只有20个唯一值的例子(你设置有籽),我认为这是更快地做到这一点:
- 分配ID给每个独特的行然后
- 在每个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
我猜rbind
和merge
s就使这个解决方案相对更昂贵与不同的数据。
我在这里被这里所吸引,因为@ flodel在R博客上看到过你的帖子。连锁反应。 – Frank