2015-06-15 14 views
21

Angenommen, I fünf Vektoren haben:Verwendung identischer() in R mit mehreren Vektoren

A<-1:10 
B<-1:10 
C<-1:10 
D<-1:10 
E<-1:12 

I zwei auf einmal unter Verwendung von identischen Test könnte().

identical(A,C) 

Aber ich möchte alle von ihnen auf einmal testen, ob ANY von den anderen unterscheidet. Gibt es einen einfachen Weg, dies zu tun?

Antwort

16

ich nur eine auswählen würde, sagen A, und tut alle paarweise Vergleiche mit ihm.

all(sapply(list(B, C, D, E), FUN = identical, A)) 
# [1] FALSE 

die all() Entfernen Sie die nicht identisch sind ein (e)

sapply(list(B, C, D, E), FUN = identical, A) 
# [1] TRUE TRUE TRUE FALSE 

identical sollte sein transitiv zu sehen, also, wenn A-C identisch ist und D, dann sollten C identisch sein D .

(Danke discimus für vereinfachte Syntax @docendo.)

+2

Eine leichte Verbesserung wäre die Verwendung der all() - Funktion vor sapply(), so dass sie eine einzelne wahr/falsch zurückgibt. – Andy

10

Der erste Gedanke ist, unique auf einer Liste der Vektoren zu tun und überprüfen Sie die Länge. Wenn es zwei oder mehr Vektoren, die anders sind, dann wird die Länge der resultierenden Liste größer als 1.

length(unique(list(A,B,C,D))) == 1 
[1] TRUE 

length(unique(list(A,B,C,D,E))) == 1 
[1] FALSE 
+0

ich die Eleganz dieser Antwort ganz gern, aber Ich werde @ Gregor als das beste markieren. – Andy

+1

@Andy, es ist die bessere Antwort gegeben, dass es immer noch "identisch" verwendet. Ich hätte an die transitiven Vergleiche gedacht: P – cdeterman

9

Eine weitere Option, nur so zum Spaß:

Vectorize(identical, 'x')(list(A, B, C, D, E), C) 
2

Das ist ziemlich offensichtlich, aber: Wenn es gibt eine Menge von Elementen und eine gute Möglichkeit des Scheiterns, wollen Sie in der Lage sein, die Vergleiche kurzzuschließen. Hier ist eine Schleife für das, mit einem Beispiel:

A = sample(1e3) 
Alist <- replicate(1e6,A,simplify=FALSE) 
Alist[[2]][1e3] <- 0 

system.time({brkres <- { 
    ok=TRUE 
    for (i in seq_along(Alist)) if(!identical(Alist[[1]],Alist[[i]])){ 
    ok=FALSE 
    break 
    } 
    ok 
}}) 
# user system elapsed 
#  0  0  0 

system.time({allres <- all(sapply(Alist[-1], FUN = identical, Alist[[1]]))}) 
# user system elapsed 
# 1.66 0.03 1.68 

Wenn Sie die Alist[[2]][1e3] <- 0 Linie überspringen, so dass sie alle identisch sind, nehmen sie die gleiche Zeit.

-1

Ich hatte das gleiche Problem, entschied mich aber, eine Lösung basierend auf Reduce und eine basierend auf einer doppelten for Schleife zu implementieren.

Funktionen:

all_elements_the_same = function(list) { 

    #func to compare with 
    comparison_func = function(x, y) { 
    if (!identical(x, y)) stop() #stop function if it finds a non-identical pair 
    y #return second element 
    } 

    #run comparisons 
    trial = try({ 
    Reduce(f = comparison_func, x = list, init = list[[1]]) 
    }, silent = T) 

    #return 
    if (class(trial) == "try-error") return(F) 
    T 
} 

all_elements_the_same2 = function(list, ignore_names = F) { 
    #double loop solution 
    for (i in seq_along(list)) { 
    for (j in seq_along(list)) { 
     #skip if comparing to self or if comparison already done 
     if (i >= j) next 

     #check 
     if (!identical(list[[i]], list[[j]])) return(F) 
    } 
    } 
    T 
} 

Testobjekte:

l_testlist_ok = list(1:3, 1:3, 1:3, 1:3, 1:3, 1:3) 
l_testlist_bad = list(1:3, 1:3, 1:4, 1:3, 1:3, 1:3) 
l_testlist_bad2 = list(1:3, 1:3, 1:4, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3) 

Test-Funktionalität:

> all_elements_the_same(l_testlist_ok) 
[1] TRUE 
> all_elements_the_same(l_testlist_bad) 
[1] FALSE 
> all_elements_the_same(l_testlist_bad2) 
[1] FALSE 
> all_elements_the_same2(l_testlist_ok) 
[1] TRUE 
> all_elements_the_same2(l_testlist_bad) 
[1] FALSE 
> all_elements_the_same2(l_testlist_bad2) 
[1] FALSE 

Prüfzeit Verwendung:

> library(microbenchmark) 
> microbenchmark(all_elements_the_same(l_testlist_ok), 
+ all_elements_the_same(l_testlist_bad), 
+ all_elements_the_same(l_testlist_bad2), 
+ all_elements_the_same2(l_testlist_ok), 
+ all_elements_the_same2(l_testlist_bad), 
+ all_elements_the_same2(l_testlist_bad2), times = 1e4) 
Unit: microseconds 
            expr min  lq  mean median  uq  max neval 
    all_elements_the_same(l_testlist_ok) 19.310 25.454 28.309016 26.917 28.380 1003.228 10000 
    all_elements_the_same(l_testlist_bad) 93.624 100.938 108.890823 103.863 106.497 3130.807 10000 
    all_elements_the_same(l_testlist_bad2) 93.331 100.938 107.963741 103.863 106.497 1181.404 10000 
    all_elements_the_same2(l_testlist_ok) 48.275 53.541 57.334095 55.881 57.930 926.866 10000 
    all_elements_the_same2(l_testlist_bad) 6.144 7.315 8.437603 7.900 8.778 998.839 10000 
all_elements_the_same2(l_testlist_bad2) 6.144 7.315 8.564780 8.192 8.778 1323.594 10000 

Also scheinbar der try Teil verlangsamt es erheblich. Es kann noch Zeit sparen, die Reduce Variante zu verwenden, wenn man sehr große Objekte hat, aber für kleinere Objekte scheint die doppelte Schleife for der Weg zu sein.

0

Die schnellste und einfachste Lösung mit Rcpp:

#include <Rcpp.h> 
using namespace Rcpp; 

inline bool same(SEXP a, SEXP b) { 
    return R_compute_identical(a, b, 0); 
} 

// [[Rcpp::export]] 
bool identical_impl(List x) { 
    std::size_t n = x.size(); 
    for (std::size_t i = 1; i < n; ++i) 
     if (!same(x[0], x[i])) return false; 
    return true; 
} 

/*** R 
identical2 <- function(...) { 
    identical_impl(list(...)) 
} 
*/ 

einige Benchmarks mit anderen Lösungen:

A <- 1:10 
B <- 1:10 
C <- 1:10 
D <- 1:10 
E <- 1:12 
identical2 <- function(...) { 
    identical_impl(list(...)) 
} 
identical3 <- function(...) { 
    length(unique(list(...))) == 1L 
} 
identical4 <- function(...) { 
    l <- list(...) 
    all(vapply(l[-1], l[[1]], FUN = identical, 
       FUN.VALUE = logical(1L), USE.NAMES = FALSE)) 
} 
identical5 <- function(...) { 
    l <- list(...) 
    Vectorize(identical, 'x')(l[-1], l[[1L]]) 
} 
identical6 <- function(...) { 
    l <- list(...) 
    for (i in seq_along(l)) { 
     if (!identical(l[[1]], l[[i]])) return(FALSE) 
    } 
    return(TRUE) 
} 
identical7 <- function(...) { 
    l <- list(...) 
    for (i in seq_along(l)) { 
     for (j in seq_along(l)) { 
      if (i >= j) next 
      if (!identical(l[[1]], l[[i]])) return(FALSE) 
     } 
    } 
    return(TRUE) 
} 
library(microbenchmark) 
microbenchmark(
    identical2(A, B, C, D, E), 
    identical3(A, B, C, D, E), 
    identical4(A, B, C, D, E), 
    identical5(A, B, C, D, E), 
    identical6(A, B, C, D, E), 
    identical7(A, B, C, D, E)) 

Ergebnisse:

Unit: microseconds 
        expr min  lq  mean median  uq  max neval cld 
identical2(A, B, C, D, E) 3.401 4.3065 5.32136 5.1245 5.5420 21.529 100 a  
identical3(A, B, C, D, E) 6.480 7.8675 9.20970 8.3875 9.0175 26.739 100 b 
identical4(A, B, C, D, E) 12.233 13.5680 15.48014 14.7755 15.5455 48.333 100 c 
identical5(A, B, C, D, E) 90.177 93.1480 98.79570 95.2685 103.2765 178.657 100  e 
identical6(A, B, C, D, E) 10.683 12.0650 13.43184 12.6820 13.4060 22.314 100 c 
identical7(A, B, C, D, E) 28.202 31.0800 34.97819 32.4630 39.4960 68.902 100 d 
Verwandte Themen