2015-12-29 31 views
6

Jaki jest najszybszy sposób wykonywania wielu porównań logicznych w R?Jaki jest najszybszy sposób wykonywania wielu porównań logicznych w R?

Rozważmy na przykład wektor x

set.seed(14) 
x = sample(LETTERS[1:4], size=10, replace=TRUE) 

Chcę sprawdzić, czy każdy wpis x jest albo "A" lub "B" (a nie czegokolwiek innego). Następujące prace:

x == "A" | x == "B" 
[1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE 

Powyższy kod wykonuje trzykrotną pętlę długości całego wektora. Czy istnieje sposób, aby w pętli R pętać tylko raz i sprawdzać dla każdego elementu, czy spełnia on jeden czy inny warunek?

+3

co powiesz na: 'x% w% c (" A "," B ")' – MrFlick

+2

@MrFlick Bawiło się z synchronizacją tych dwóch opcji i naprawdę nie widzę dużej różnicy. Skala jest w nanosekundach, nawet gdy zwiększam ją, więc jestem trochę stracona – joran

+3

@joran Tak, nie wyobrażam sobie, że zobaczysz duży wzrost prędkości (i bardzo wątpię, wąskie gardło wydajności), ale jest to po prostu alternatywna składnia. – MrFlick

Odpowiedz

12

Jeśli Twoim celem jest tylko, aby jeden przejazd, który jest bardzo proste do napisania w RCPP, nawet jeśli nie masz dużego doświadczenia z C++:

#include <Rcpp.h> 

// [[Rcpp::export]] 
Rcpp::LogicalVector single_pass(Rcpp::CharacterVector x, Rcpp::String a, Rcpp::String b) { 
    R_xlen_t i = 0, n = x.size(); 
    Rcpp::LogicalVector result(n); 

    for (; i < n; i++) { 
    result[i] = (x[i] == a || x[i] == b); 
    } 

    return result; 
} 

dla takiego małego obiekt, który wykorzystano w przykładzie, niewielkiego narzutu .Call (przypuszczalnie) maski prędkość wersji RCPP,

r_fun <- function(X) X == "A" | X == "B" 
## 
cpp_fun <- function(X) single_pass(X, "A", "B") 
## 
all.equal(r_fun(x), cpp_fun(x)) 
#[1] TRUE 
microbenchmark::microbenchmark(
    r_fun(x), cpp_fun(x), times = 1000L) 
#Unit: microseconds 
#expr   min lq  mean median  uq max neval 
#r_fun(x) 1.499 1.584 1.974156 1.6795 1.8535 37.903 1000 
#cpp_fun(x) 1.860 2.334 3.042671 2.7450 3.1140 51.870 1000 

Ale dla większych wektorów (jestem zakładając, to y nasze prawdziwe intencje), to znacznie szybciej:

x2 <- sample(LETTERS, 10E5, replace = TRUE) 
## 
all.equal(r_fun(x2), cpp_fun(x2)) 
# [1] TRUE 
microbenchmark::microbenchmark(
    r_fun(x2), cpp_fun(x2), times = 200L) 
#Unit: milliseconds 
#expr    min  lq  mean median  uq  max neval 
#r_fun(x2) 78.044518 79.344465 83.741901 80.999538 86.368627 149.5106 200 
#cpp_fun(x2) 7.104929 7.201296 7.797983 7.605039 8.184628 10.7250 200 

Oto quick attempt w uogólniając powyższe, jeśli masz jakieś zastosowanie dla niego.