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

时间:2014-12-05 21:32:01

标签: r

使用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()告诉你什么是不相等的,如果他们不平等。

2 个答案:

答案 0 :(得分:10)

这是一个选项:

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

它比你的好,因为它会检测barfaz何时相同,即使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