2016-01-30 23 views
5

Sarei sorpreso se questo non fosse un dup, ma non sono riuscito a trovare una soluzione.Test di uguaglianza vettorizzati

Capisco i limiti di == per verificare l'uguaglianza dei numeri in virgola mobile. Si dovrebbe usare all.equal

0.1 + 0.2 == 0.3 
# FALSE 
all.equal(0.1 + 0.2, 0.3) 
# TRUE 

Ma == ha il vantaggio di essere vettorializzare:

set.seed(1) 
Df <- data.frame(x = sample(seq(-1, 1, by = 0.1), size = 100, replace = TRUE), 
       y = 0.1) 
Df[Df$x > 0 & Df$x < 0.2,] 
## x y 
## 44 0.1 0.1 
## 45 0.1 0.1 

# yet 
sum(Df$x == Df$y) 
# [1] 0 

posso scrivere una (cattiva) funzione me stesso:

All.Equal <- function(x, y){ 
    stopifnot(length(x) == length(y)) 
    out <- logical(length(x)) 
    for (i in seq_along(x)){ 
    out[i] <- isTRUE(all.equal(x[i], y[i])) 
    } 
    out 
} 

sum(All.Equal(Df$x, Df$y)) 

che dà la risposta corretta, ma ha ancora una lunga strada da percorrere.

microbenchmark::microbenchmark(All.Equal(Df$x, Df$y), Df$x == Df$y) 
Unit: microseconds 
        expr  min  lq  mean  median  uq  max neval cld 
All.Equal(Df$x, Df$y) 9954.986 10298.127 20382.24436 10511.5360 10798.841 915182.911 100 b 
      Df$x == Df$y 16.857 19.265 29.06261 30.8535 38.529  45.151 100 a 

Un'altra opzione potrebbe essere:

All.equal.abs <- function(x,y){ 
    tol <- .Machine$double.eps^0.5 
    abs(x - y) < tol 
} 

che svolge in modo paragonabile a ==.

Che cos'è una funzione esistente che esegue questa attività?

+0

più vicino mi viene in mente è 'con (Df, mapply (function (a, b) IsTrue (all.equal (a, b)), x, y))', ma che probabilmente sarebbe meglio di quello che hai già fatto. Potresti ottenere un leggero aumento della velocità usando '.mapply()' (bare bone 'mapply()'). –

+4

'abs (x-y) fishtank

risposta

0

Non si può fare un test di benchmark, ma la funzione di vettorizzazione all.equal potrebbe funzionare:

All.equal <- Vectorize(all.equal, c("target", "current")) 
sum(All.equal(Df$x, Df$y)==T) 
2

Vectorize() risulta essere un'opzione lenta. Come suggerisce @fishtank nel commento, la soluzione migliore viene dal verificare se la differenza assoluta è inferiore a un valore di tolleranza, ad esempio is_equal_tol() dal basso.

set.seed(123) 
a <- sample(1:10, size = 50, replace = T) 
b <- sample(a) 

is_equal_tol <- function(x, y, tol = .Machine$double.eps^0.5) { 
    abs(x - y) < tol 
} 

is_equal_vec <- Vectorize(all.equal, c("target", "current")) 

is_equal_eq <- function(x, y) x == y 

microbenchmark::microbenchmark(is_equal_eq(a, b), 
           is_equal_tol(a, b), 
           isTRUE(is_equal_vec(a, b)), 
           times = 1000L) 

Unit: nanoseconds 
         expr  min  lq  mean median  uq  max neval 
      is_equal_eq(a, b)  0  856 1545.797 1284 2139 14113 1000 
     is_equal_tol(a, b) 1711 2567 4991.377 4278 6843 27370 1000 
isTRUE(is_equal_vec(a, b)) 2858445 3008552 3258916.503 3082964 3204204 46130260 1000 
+1

Non mostri la tua generazione 'a' e' b', ma con i tuoi risultati in nanosecondi penso che dovresti renderli più lunghi. – Gregor

+0

@ Gregor Hai ragione. Ho modificato l'esempio per fornire l'esempio completo. Grazie! –