简体   繁体   English

R:多个对象的all.equal()?

[英]R: all.equal() for multiple objects?

What is the best way to compare more than two objects with all.equal() ? 使用all.equal()比较两个以上对象的最佳方法是什么?

Here's one way: 这是一种方式:

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 pointed out that the one-liner above only tells you whether the objects are all equal or not, whereas all.equal() tells you what isn't equal about them if they aren't equal. 更新: @BrodieG指出上面的单行只告诉你对象是否全部相等,而all.equal()告诉你,如果它们不相等,它们是不相等的。

Here is an option: 这是一个选项:

objs <- mget(c("foo", "bar", "faz"))
outer(objs, objs, Vectorize(all.equal))

It's better than yours because it will detect when bar and faz are the same, even when foo isn't. 它比你的好,因为它会检测barfaz何时相同,即使foo不是。 That said, it does a lot of unnecessary comparisons and will be slow. 也就是说,它做了很多不必要的比较,并且会很慢。 For example, if we change foo to be letters[1:10] we get: 例如,如果我们将foo改为letters[1:10]我们得到:

    foo         bar         faz        
foo TRUE        Character,2 Character,2
bar Character,2 TRUE        TRUE       
faz Character,2 TRUE        TRUE 

For details on what went wrong, just subset: 有关出错的详细信息,只需要子集:

outer(objs, objs, Vectorize(all.equal))[1, 2]

Produces: 生产:

[[1]]
[1] "Modes: character, numeric"              
[2] "target is character, current is numeric"       

If all you care about is that all the objects must be all.equal , then your solution is pretty good. 如果您关心的是所有对象必须all.equal ,那么您的解决方案非常好。

Also, as per comments to limit some of the duplicate calculations: 此外,根据评论限制一些重复计算:

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

Produces 产生

    foo  bar         faz        
foo NULL Character,2 Character,2
bar NULL NULL        TRUE       
faz NULL NULL        NULL         

This still shows the full matrix, but makes it obvious what comparisons produced what. 这仍然显示了完整的矩阵,但很明显比较产生了什么。

I think this comes as close to the behavior of all.equal() as possible. 我认为这与all.equal()的行为尽可能接近。

It returns TRUE if the objects are all equal and a list of pairwise comparisons otherwise. 如果对象全部相等则返回TRUE否则返回成对比较列表。 It returns a single-item list if only two objects are compared for consistency of output. 如果仅比较两个对象以确保输出的一致性,则返回单项列表。

# 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)}
  }

Testing 1, 2: 测试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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM