Frage Identische () in R mit mehreren Vektoren verwenden


Angenommen, ich habe fünf Vektoren:

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

Ich könnte zwei auf einmal mit identischen () testen.

identical(A,C)

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


23
2018-06-15 16:35


Ursprung


Antworten:


Ich würde nur einen auswählen, sagen Aund mache alle paarweisen Vergleiche damit.

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

Entferne das all() um die nicht identischen zu sehen

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

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

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


18
2018-06-15 16:49



Der erste Gedanke ist zu tun unique auf einer Liste der Vektoren und überprüfen Sie die Länge. Wenn zwei oder mehr Vektoren unterschiedlich sind, ist 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

11
2018-06-15 16:43



Eine weitere Option, nur zum Spaß:

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

9
2018-06-15 17:50



Das ist ziemlich offensichtlich, aber: Wenn es viele Elemente und gute Ausfallwahrscheinlichkeiten gibt, sollten Sie in der Lage sein, die Vergleiche kurzzuschließen. Hier ist eine Schleife dafür, 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 das überspringen Alist[[2]][1e3] <- 0 Linie, so dass sie alle identisch sind, nehmen sie die gleiche Zeit.


2
2018-06-15 21:48



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 

0
2017-07-28 10:41



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

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)

Testfunktionalitä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

Testzeit verwenden:

> 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 anscheinend try Teil verlangsamt es erheblich. Es kann noch Zeit sparen, um das zu verwenden Reduce Variante, wenn man sehr große Objekte hat, aber für kleinere Objekte doppelt for Schleife scheint der Weg zu gehen.


-1
2017-07-06 10:46