Ich habe die Angewohnheit, ähnliche Aufgaben in einer einzigen Zeile zusammenzufassen. Wenn ich zum Beispiel nach und in einer Datentabelle filtern a
muss b
, füge c
ich sie in einer []
mit UNDs zusammen. Gestern habe ich festgestellt, dass dies in meinem speziellen Fall unglaublich langsam war und stattdessen Verkettungsfilter getestet. Ich habe unten ein Beispiel aufgenommen.
Zuerst setze ich den Zufallszahlengenerator, lade data.table und erstelle einen Dummy-Datensatz.
# Set RNG seed
set.seed(-1)
# Load libraries
library(data.table)
# Create data table
dt <- data.table(a = sample(1:1000, 1e7, replace = TRUE),
b = sample(1:1000, 1e7, replace = TRUE),
c = sample(1:1000, 1e7, replace = TRUE),
d = runif(1e7))
Als nächstes definiere ich meine Methoden. Der erste Ansatz kettet Filter zusammen. Das zweite UND setzt die Filter zusammen.
# Chaining method
chain_filter <- function(){
dt[a %between% c(1, 10)
][b %between% c(100, 110)
][c %between% c(750, 760)]
}
# Anding method
and_filter <- function(){
dt[a %between% c(1, 10) & b %between% c(100, 110) & c %between% c(750, 760)]
}
Hier überprüfe ich, ob sie die gleichen Ergebnisse liefern.
# Check both give same result
identical(chain_filter(), and_filter())
#> [1] TRUE
Schließlich vergleiche ich sie.
# Benchmark
microbenchmark::microbenchmark(chain_filter(), and_filter())
#> Unit: milliseconds
#> expr min lq mean median uq max
#> chain_filter() 25.17734 31.24489 39.44092 37.53919 43.51588 78.12492
#> and_filter() 92.66411 112.06136 130.92834 127.64009 149.17320 206.61777
#> neval cld
#> 100 a
#> 100 b
Erstellt am 25.10.2019 vom reprex-Paket (v0.3.0)
In diesem Fall reduziert die Verkettung die Laufzeit um ca. 70%. Warum ist das so? Ich meine, was ist unter der Haube in der Datentabelle los? Ich habe keine Warnungen vor der Verwendung gesehen &
, daher war ich überrascht, dass der Unterschied so groß ist. In beiden Fällen bewerten sie die gleichen Bedingungen, so dass dies kein Unterschied sein sollte. Im AND-Fall &
handelt es sich um einen Schnelloperator, der die Datentabelle nur einmal filtern muss (dh unter Verwendung des aus den ANDs resultierenden logischen Vektors), im Gegensatz zum dreimaligen Filtern im Verkettungsfall.
Bonus-Frage
Gilt dieses Prinzip für Datentabellenoperationen im Allgemeinen? Ist die Modularisierung von Aufgaben immer eine bessere Strategie?
quelle
base
Beobachtung mit Vektoren machen, indem Sie Folgendes tun:chain_vec <- function() { x <- which(a < .001); x[which(b[x] > .999)] }
undand_vec <- function() { which(a < .001 & b > .999) }
. (woa
undb
sind Vektoren gleicher Länge vonrunif
- ich haben = 1e7
für diese Cutoffs verwendet).Antworten:
Meistens wurde die Antwort bereits in den Kommentaren gegeben: Die "Verkettungsmethode" für
data.table
ist in diesem Fall schneller als die "Anding-Methode", da die Verkettung die Bedingungen nacheinander ausführt. Da jeder Schritt die Größe des Schrittes verringertdata.table
, muss für den nächsten weniger bewertet werden. "Anding" wertet jedes Mal die Bedingungen für die Daten in voller Größe aus.Wir können dies anhand eines Beispiels demonstrieren: Wenn die einzelnen Schritte die Größe von NICHT verringern
data.table
(dh die zu überprüfenden Bedingungen sind für beide Ansätze gleich):Verwenden Sie dieselben Daten, aber das
bench
Paket, das automatisch überprüft, ob die Ergebnisse identisch sind:Wie Sie hier sehen können, ist der Anding-Ansatz in diesem Fall 2,43-mal schneller . Das bedeutet, dass das Verketten tatsächlich einen gewissen Overhead verursacht , was darauf hindeutet, dass Anding normalerweise schneller sein sollte. AUSSER wenn die Bedingungen die Größe des
data.table
Schrittes Schritt für Schritt verringern . Theoretisch könnte der Verkettungsansatz sogar langsamer sein (selbst wenn der Overhead beiseite gelassen wird), nämlich wenn eine Bedingung die Größe der Daten erhöhen würde. Aber praktisch denke ich, dass dies nicht möglich ist, da das Recycling von logischen Vektoren nicht erlaubt istdata.table
. Ich denke, das beantwortet Ihre Bonusfrage.Zum Vergleich: Originalfunktionen auf meinem Computer mit
bench
:quelle