2014-12-05 19 views
6

Jaki jest najlepszy sposób porównania więcej niż dwóch obiektów z all.equal()?R: all.equal() dla wielu obiektów?

Oto jeden ze sposobów:

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 wskazał, że jedna wkładka powyżej tylko mówi, czy obiekty są równe, czy nie, natomiast all.equal() mówi, co nie jest równa o nich, jeśli nie są równi.

Odpowiedz

1

Myślę, że to jest tak bliskie zachowanie się jak to tylko możliwe all.equal().

Zwraca TRUE, jeśli wszystkie obiekty są równe, a lista porównań parami jest inna. Zwraca listę pojedynczych elementów, jeśli porównuje się tylko dwa obiekty dla spójności wyniku.

# 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:

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 
6

Oto opcja:

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

To lepsze niż twoje, ponieważ będzie to wykryć, kiedy barfaz i są takie same, nawet gdy nie jest foo. Powiedział, że robi wiele niepotrzebnych porównań i będzie powolny. Na przykład, jeśli zmienimy foo być letters[1:10] otrzymujemy:

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

Szczegółowe informacje na temat tego, co poszło nie tak, po prostu podzbiór:

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

Produkuje:

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

Jeśli wszystko obchodzi o to, że wszystkie obiekty muszą być all.equal, wtedy twoje rozwiązanie jest całkiem dobre.

Ponadto, zgodnie z uwagami do ograniczenia niektórych zduplikowanych obliczeń:

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 

Produkuje

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

to nadal pokazuje pełną matrycę, ale to oczywiste, co sprawia, że ​​porównania produkowane co.

+0

Dobry pomysł - jest w stanie wykryć różnice między zakaz pierwszych elementów byłby przydatny. A co z generowaniem macierzy par nazw, aby uniknąć autoreferencji w 'outer()'? 'names <- c (" foo "," bar "," faz "); pary <- t (combn (imiona, 2)); zastosuj (pary, 1, funkcja (x) all.equal (get (x [1]), get (x [2]))) ' – treysp

+0

@treysp, uzgodniono, zobacz moją modyfikację. – BrodieG

Powiązane problemy