Ich habe versucht, ein wenig zu testen, die effizienteste Möglichkeit, NA in Datenrahmen zu ersetzen.Diskrepanzen in Benchmark und Bearbeitungszeit Ergebnisse
Ich begann mit einem Vergleich der NAs mit 0 Ersatzlösungen auf einer 1 Million Zeile, 12 Spalten-Datensatz. Werfen alle Rohr-fähig diejenigen in microbenchmark
Ich habe die folgenden Ergebnisse.
Frage 1: Gibt es eine Möglichkeit, die Teilmenge links Zuweisungsanweisungen (e.g.:df1[is.na(df1)] < zu testen - 0) in der benchmark
Funktion?
library(dplyr)
library(tidyr)
library(microbenchmark)
set.seed(24)
df1 <- as.data.frame(matrix(sample(c(NA, 1:5), 1e6 *12, replace=TRUE),
dimnames = list(NULL, paste0("var", 1:12)), ncol=12))
op <- microbenchmark(
mut_all_ifelse = df1 %>% mutate_all(funs(ifelse(is.na(.), 0, .))),
mut_at_ifelse = df1 %>% mutate_at(funs(ifelse(is.na(.), 0, .)), .cols = c(1:12)),
# df1[is.na(df1)] <- 0 would sit here, but I can't make it work inside this function
replace = df1 %>% replace(., is.na(.), 0),
mut_all_replace = df1 %>% mutate_all(funs(replace(., is.na(.), 0))),
mut_at_replace = df1 %>% mutate_at(funs(replace(., is.na(.), 0)), .cols = c(1:12)),
replace_na = df1 %>% replace_na(list(var1 = 0, var2 = 0, var3 = 0, var4 = 0, var5 = 0, var6 = 0, var7 = 0, var8 = 0, var9 = 0, var10 = 0, var11 = 0, var12 = 0)),
times = 1000L
)
print(op) #standard data frame of the output
Unit: milliseconds
expr min lq mean median uq max neval
mut_all_ifelse 769.87848 844.5565 871.2476 856.0941 895.4545 1274.5610 1000
mut_at_ifelse 713.48399 847.0322 875.9433 861.3224 899.7102 1006.6767 1000
replace 258.85697 311.9708 334.2291 317.3889 360.6112 455.7596 1000
mut_all_replace 96.81479 164.1745 160.6151 167.5426 170.5497 219.5013 1000
mut_at_replace 96.23975 166.0804 161.9302 169.3984 172.7442 219.0359 1000
replace_na 103.04600 161.2746 156.7804 165.1649 168.3683 210.9531 1000
boxplot(op) #boxplot of output
library(ggplot2) #nice log plot of the output
qplot(y=time, data=op, colour=expr) + scale_y_log10()
die Teilmenge Zuweisungsoperator Um zu testen, die ich ursprünglich diese Tests laufen hatte.
set.seed(24)
> Book1 <- as.data.frame(matrix(sample(c(NA, 1:5), 1e8 *12, replace=TRUE),
+ dimnames = list(NULL, paste0("var", 1:12)), ncol=12))
> system.time({
+ Book1 %>% mutate_all(funs(ifelse(is.na(.), 0, .))) })
user system elapsed
52.79 24.66 77.45
>
> system.time({
+ Book1 %>% mutate_at(funs(ifelse(is.na(.), 0, .)), .cols = c(1:12)) })
user system elapsed
52.74 25.16 77.91
>
> system.time({
+ Book1[is.na(Book1)] <- 0 })
user system elapsed
16.65 7.86 24.51
>
> system.time({
+ Book1 %>% replace_na(list(var1 = 0, var2 = 0, var3 = 0, var4 = 0, var5 = 0, var6 = 0, var7 = 0, var8 = 0, var9 = 0,var10 = 0, var11 = 0, var12 = 0)) })
user system elapsed
3.54 2.13 5.68
>
> system.time({
+ Book1 %>% mutate_at(funs(replace(., is.na(.), 0)), .cols = c(1:12)) })
user system elapsed
3.37 2.26 5.63
>
> system.time({
+ Book1 %>% mutate_all(funs(replace(., is.na(.), 0))) })
user system elapsed
3.33 2.26 5.58
>
> system.time({
+ Book1 %>% replace(., is.na(.), 0) })
user system elapsed
3.42 1.09 4.51
In diesen Tests die Basis replace()
in erster Stelle steht. In den Benchmarking-Studien fällt die replace
weiter zurück in den Reihen, während die tidyrreplace_na()
Siege (durch die Nase) die singulären Tests laufen wiederholt und auf unterschiedlichen Formen und Größen von Datenrahmen immer die Basis replace()
in Führung finden.
Frage 2: Wie könnte die Benchmark-Leistung das einzige Ergebnis sein, das so weit von den einfachen Testergebnissen abweicht?
Mehr verblüffend - Frage 3: Wie kann das alles mutate_all/_at(replace())
Arbeit schneller als die einfachen replace()
? Viele Leute berichten dies: http://datascience.la/dplyr-and-a-very-basic-benchmark/ (und alle Links in diesem Artikel), aber ich habe immer noch keine Erklärung dafür gefunden, warum darüber hinaus Hashing und C++ verwendet werden.
mit besonderem Dank schon nach Tyler Rinker: https://www.r-bloggers.com/microbenchmarking-with-r/ und akrun: https://stackoverflow.com/a/41530071/5088194
Versuchen Sie, es mit '{}' - '{df1 [is.na (df1)] <- 0}' zu umhüllen. Übrigens, beachten Sie, dass 'df1' und' Book1' "Integer" sind und Sie in allen Fällen auf "numerisch" angewiesen sind. Das Ersetzen von "0" durch "0L" sollte die Geschwindigkeit in allem erhöhen. Beachten Sie beim Benchmarking auch, dass Book1 [is.na (Book1)] <- 0' das tatsächliche 'Book1' durch ein erzwungenes' Book1' von "integer" in "numeric" ersetzt und alle nachfolgenden Fälle den Vorteil von _not_ haben. zwingen müssen. Um zu vermeiden, dass der ursprüngliche Datenumbruch mit einer Funktion oder "local" erzwungen wird. Schließlich denke ich, ein effizienter Weg ist für (j in 1: ncol (df1)) df1 [[j]] [is.na (df1 [[j]])] = 0L'. –
@alexis_laz: In der Tat! Das beantwortete die meisten Fragen und half mir, zu sehen, wo/wie Mutables in R arbeiten. Möchten Sie das in eine Antwort einfügen, damit ich sie auswählen kann? Könnten Sie außerdem möglicherweise eine Erklärung hinzufügen, warum Ihre for-Schleife mit (oder sogar ohne) der vereinfachenden Teilmenge so viel schneller funktioniert als die übrigen Optionen? –
Ich habe eine erweiterte Antwort hinzugefügt. Die 'for'-Schleife gehört zu den schnellsten Alternativen, weil sie das Minimum macht, das getan werden muss, um einen Wert in einem Vektor zu ersetzen. Die ganze Teilmenge, die in der 'for'-Schleife stattfindet, ist nur mit den primitiven Funktionen und nicht mit den" data.frame "-Methoden für' ['und' [<-', die einen signifikanten Overhead enthalten. Die einzige Sache, die eine solche Reihe von Operationen innerhalb der Schleife "schlagen" kann (und nicht um eine signifikante Menge), ist das Modifizieren an Ort und Stelle; etwas, das Base R nicht unterstützt. –