2016-01-30 8 views
5

Ich würde mich wundern, wenn dies kein Dup, aber ich konnte keine Lösung finden.Vektorisierte Gleichheitsprüfung

Ich verstehe die Einschränkungen von == zum Testen der Gleichheit von Gleitkommazahlen. Man sollte all.equal

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

Aber == den Vorteil hat, von vektorisiert werden:

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 

Ich kann eine (sehr schlecht) schreiben funktionieren mich:

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)) 

, die die richtige Antwort gibt, aber es ist noch ein weiter Weg.

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 

könnte eine weitere Option:

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

, die zu == vergleichbar führt.

Was ist eine vorhandene Funktion, die diese Aufgabe ausführt?

+0

Closest ich denken kann, ist 'mit (Df, mapply (function (a, b) IsTrue (all.equal (a, b)), x, y))' aber das wäre wahrscheinlich nicht besser sein als das, was Sie bereits getan haben. Mit '.mapply()' (bare bones 'mapply()') können Sie die Geschwindigkeit etwas erhöhen. –

+4

'Abs (x-y) fishtank

Antwort

0

Kann eine Benchmark-Test nicht, aber Vektorisieren die all.equal Funktion funktionieren könnte:

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

Vectorize() dreht sich eine langsame Option erwiesen. Wie @fishtank im Kommentar vorschlägt, kommt die beste Lösung von der Überprüfung, ob die absolute Differenz kleiner als ein Toleranzwert ist, d. H. is_equal_tol() von unten.

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

Sie zeigen Ihre 'a' und' b' Generation nicht, aber mit Ihren Ergebnissen in Nanosekunden sollten Sie sie zu längeren Vektoren machen. – Gregor

+0

@Gregor Du hast Recht. Ich habe das Beispiel bearbeitet, um das vollständige Beispiel zu geben. Vielen Dank! –

Verwandte Themen