使用all.equal()
比较两个以上对象的最佳方法是什么?
这是一种方式:
foo <- c(1:10)
bar <- letters[1:10]
baz <- c(1:10)
# doesn't work because all.equal() returns a character vector when objects not all equal
all(sapply(list(bar, baz), all.equal, foo))
# this works
mode(sapply(list(bar, baz), all.equal, foo)) == "logical" #FALSE
bar <- c(1:10)
mode(sapply(list(bar, baz), all.equal, foo)) == "logical" #TRUE
UPDATE: @BrodieG指出上面的单行只告诉你对象是否全部相等,而all.equal()
告诉你什么是不相等的,如果他们不平等。
答案 0 :(得分:10)
这是一个选项:
objs <- mget(c("foo", "bar", "faz"))
outer(objs, objs, Vectorize(all.equal))
它比你的好,因为它会检测bar
和faz
何时相同,即使foo
不是。也就是说,它做了很多不必要的比较,并且会很慢。例如,如果我们将foo
更改为letters[1:10]
,我们会得到:
foo bar faz
foo TRUE Character,2 Character,2
bar Character,2 TRUE TRUE
faz Character,2 TRUE TRUE
有关出错的详细信息,只需要子集:
outer(objs, objs, Vectorize(all.equal))[1, 2]
产地:
[[1]]
[1] "Modes: character, numeric"
[2] "target is character, current is numeric"
如果您关心的是所有对象必须是all.equal
,那么您的解决方案非常好。
另外,根据评论限制一些重复计算:
res <- outer(objs, objs, function(x, y) vector("list", length(x)))
combs <- combn(seq(objs), 2)
res[t(combs)] <- Vectorize(all.equal)(objs[combs[1,]], objs[combs[2,]])
res
可生产
foo bar faz
foo NULL Character,2 Character,2
bar NULL NULL TRUE
faz NULL NULL NULL
这仍然显示完整的矩阵,但很明显比较产生了什么。
答案 1 :(得分:3)
我认为这与all.equal()
的行为尽可能接近。
如果对象全部相等则返回TRUE
,否则返回成对比较列表。如果仅比较两个对象以确保输出的一致性,则返回单项列表。
# function: all.equal.mult()
# description: compares >=2 objects with all.equal()
# input: >=2 comma-separated object names
# output: TRUE or list of pairwise all.equal() object comparisons
# examples:
# foo <- c(1:10)
# bar <- c(1:10)
# foz <- c(1:10)
# baz <- letters[1:10]
#
# all.equal.mult(foo, bar) # TRUE
# all.equal.mult(foo, baz) # results of all.equal(foo, baz) as one-item list
# all.equal.mult(foo, bar, foz) # TRUE
# all.equal.mult(foo, bar, baz) # list of pairwise all.equal() comparisons among objects
all.equal.mult <- function(...) {
# more than one object required
if (length(list(...)) < 2) stop("More than one object required")
# character vector of object names
names <- as.character(substitute(list(...)))[-1L]
# matrix of object name pairs
pairs <- t(combn(names, 2))
# if only two objects, return one item list containing all.equal() for them
if (nrow(pairs) == 1) return(list(all.equal(get(pairs[1,1]), get(pairs[1,2]))))
# function: eq.fun()
# description: applies all.equal() to two quoted names of objects
# input: two quoted names of objects
# output: list containing all.equal() comparison and "[obj1] vs. [obj2]"
# examples:
# x <- 1
# y <- 1
# z <- 2
# eq.fun("x", "y") # list(TRUE, "x vs. y")
# eq.fun("x", "z") # list("Mean relative difference: 1", "x vs. z")
eq.fun <- function(x, y) {
all.eq <- all.equal(get(x, inherits=TRUE), get(y, inherits=TRUE))
name <- paste0(x, " vs. ", y)
return(list(all.eq, name))
}
# list of eq.fun object comparisons
out <- vector(mode="list", length=nrow(pairs))
for (x in 1:nrow(pairs)) {
eq.list <- eq.fun(pairs[x, 1], pairs[x, 2])
out[[x]] <- eq.list[[1]]
names(out)[x] <- eq.list[[2]]
}
# return TRUE if all objects equal, comparison list otherwise
if (mode(unlist(out)) == "logical") {return(TRUE)} else {return(out)}
}
测试1,2:
foo <- c(1:10)
bar <- c(1:10)
foz <- c(1:10)
baz <- letters[1:10]
all.equal.mult(foo) # Error
all.equal.mult(foo, bar) # TRUE
all.equal.mult(foo, baz) # results of all.equal(foo, baz) as one-item list
all.equal.mult(foo, bar, foz) # TRUE
all.equal.mult(foo, bar, baz) # list of pairwise all.equal() comparisons among objects