提问人:Krithi07 提问时间:6/13/2019 更新时间:1/22/2021 访问量:1405
比较 R 中相等的 2 个数据帧
Compare 2 dataframes for equality in R
问:
我有 2 个数据帧,有 2 个相同的列。我想检查数据集是否相同。原始数据集有一些 700K 记录,但我正试图找到一种使用虚拟数据集的方法
我尝试使用比较、相同、全部、all_equal等。他们都没有给我一个 True。
虚拟数据集是 -
a <- data.frame(x = 1:10, b = 20:11)
c <- data.frame(x = 10:1, b = 11:20)
all(a==c)
[1] FALSE
compare(a,c)
FALSE [FALSE, FALSE]
identical(a,c)
[1] FALSE
all.equal(a,c)
[1] "Component “x”: Mean relative difference: 0.9090909" "Component “b”: Mean relative difference: 0.3225806"
数据集完全相同,只是记录的顺序不同。如果这些函数仅在数据集是彼此的镜像时才起作用,那么我必须尝试其他方法。如果是这种情况,有人可以帮忙如何获得这 2 个数据集的 True(无序)
答:
5赞
Gregor Thomas
6/13/2019
#1
dplyr
在数据帧上的工作,我建议setdiff
library(dplyr)
nrow(setdiff(a, c)) == 0 & nrow(setdiff(c, a)) == 0
# [1] TRUE
请注意,这不会考虑重复行的数量。(即,如果一行有多个副本,并且该行只有一个副本,它仍将返回 )。不确定您希望如何处理重复的行...a
c
TRUE
如果您确实关心具有相同数量的重复项,那么我建议两种可能性:(a) 添加一个 ID 列来区分重复项并使用上述方法,或者 (b) 排序、重置行名(令人讨厌)并使用 .identical
(a) 添加 ID 列
library(dplyr)
a_id = group_by_all(a) %>% mutate(id = row_number())
c_id = group_by_all(c) %>% mutate(id = row_number())
nrow(setdiff(a_id, c_id)) == 0 & nrow(setdiff(c_id, a_id)) == 0
# [1] TRUE
(b) 排序
a_sort = a[do.call(order, a), ]
row.names(a_sort) = NULL
c_sort = c[do.call(order, c), ]
row.names(c_sort) = NULL
identical(a_sort, c_sort)
# [1] TRUE
1赞
Rui Barradas
6/13/2019
#2
也许您需要一个在比较之前对列进行排序的函数。但是在大型数据帧上会很慢。
unordered_equal <- function(X, Y, exact = FALSE){
X[] <- lapply(X, sort)
Y[] <- lapply(Y, sort)
if(exact) identical(X, Y) else all.equal(X, Y)
}
unordered_equal(a, c)
#[1] TRUE
unordered_equal(a, c, TRUE)
#[1] TRUE
a$x <- a$x + .Machine$double.eps
unordered_equal(a, c)
#[1] TRUE
unordered_equal(a, c, TRUE)
#[1] FALSE
评论
0赞
Gregor Thomas
6/13/2019
lapply(X, sort)
将独立对列进行排序,这似乎很糟糕。给定 , , , 我认为 OP 希望 X 和 Y 为 TRUE,但 X 和 Z 为 FALSE,但这会说所有对都为 TRUE。X = data.frame(1:2, 1:2)
Y = data.frame(2:1, 2:1)
Z = data.frame(1:2, 2:1)
0赞
Gregor Thomas
6/13/2019
如果您使用 etc.,它将按所有列对行进行排序。do.call(order, X)
0赞
Rui Barradas
6/13/2019
@Gregor谢谢,我没有想到这一点。我已经在评论中询问了 OP 是否这是预期的问题。
0赞
Krithi07
6/13/2019
@Gregor,do.call(order, X) 似乎并没有按照我们想要的方式工作。x = data.frame(1:2, 2:1), do.call(order,x) 给出一个具有 2 个值的对象,(1,2)
0赞
Gregor Thomas
6/13/2019
“是”给出了行顺序,因此实际上要像我的答案一样对数据框进行重新排序。do.call(order, x)
x[do.call(order, x), ]
0赞
jay.sf
6/13/2019
#3
基本上,您想要的可能是比较有序的基础矩阵。
all.equal(matrix(unlist(a[order(a[1]), ]), dim(a)),
matrix(unlist(c[order(c[1]), ]), dim(c)))
# [1] TRUE
identical(matrix(unlist(a[order(a[1]), ]), dim(a)),
matrix(unlist(c[order(c[1]), ]), dim(c)))
# [1] TRUE
为了方便起见,您可以将其包装成一个函数:
om <- function(d) matrix(unlist(d[order(d[1]), ]), dim(d))
all.equal(om(a), om(c))
# [1] TRUE
0赞
George Pipis
1/22/2021
#4
您可以使用名为 waldo 的新软件包
library(waldo)
a <- data.frame(x = 1:10, b = 20:11)
c <- data.frame(x = 10:1, b = 11:20)
compare(a,c)
你会得到:
`old$x`: 1 2 3 4 5 6 7 8 9 10 and 9 more...
`new$x`: 10 ...
`old$b`: 20 19 18 17 16 15 14 13 12 11 and 9 more...
`new$b`:
评论
X
Z