R Language
Code-Profiling
Suche…
Systemzeit
Die Systemzeit gibt die CPU-Zeit an, die zum Ausführen eines R-Ausdrucks erforderlich ist. Beispiel:
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Sie können größere Codeteile mithilfe von geschweiften Klammern hinzufügen:
system.time({
library(numbers)
Primes(1,10^5)
})
Oder verwenden Sie es zum Testen von Funktionen:
fibb <- function (n) {
if (n < 3) {
return(c(0,1)[n])
} else {
return(fibb(n - 2) + fibb(n -1))
}
}
system.time(fibb(30))
proc.time ()
Im einfachsten proc.time()
gibt proc.time()
die gesamte verstrichene CPU-Zeit in Sekunden für den aktuellen Prozess an. Wenn Sie es in der Konsole ausführen, erhalten Sie folgende Ausgabe:
proc.time()
# user system elapsed
# 284.507 120.397 515029.305
Dies ist besonders nützlich für das Benchmarking bestimmter Codezeilen. Zum Beispiel:
t1 <- proc.time()
fibb <- function (n) {
if (n < 3) {
return(c(0,1)[n])
} else {
return(fibb(n - 2) + fibb(n -1))
}
}
print("Time one")
print(proc.time() - t1)
t2 <- proc.time()
fibb(30)
print("Time two")
print(proc.time() - t2)
Dies ergibt die folgende Ausgabe:
source('~/.active-rstudio-document')
# [1] "Time one"
# user system elapsed
# 0 0 0
# [1] "Time two"
# user system elapsed
# 1.534 0.012 1.572
system.time()
ist ein Wrapper für proc.time()
, der die abgelaufene Zeit für einen bestimmten Befehl / Ausdruck zurückgibt.
print(t1 <- system.time(replicate(1000,12^2)))
## user system elapsed
## 0.000 0.000 0.002
Beachten Sie, dass das zurückgegebene Objekt der Klasse proc.time
etwas komplizierter ist, als es auf der Oberfläche erscheint:
str(t1)
## Class 'proc_time' Named num [1:5] 0 0 0.002 0 0
## ..- attr(*, "names")= chr [1:5] "user.self" "sys.self" "elapsed" "user.child" ...
Linienprofilierung
Ein Paket für das Line-Profiling ist Lineprof, das von Hadley Wickham geschrieben und verwaltet wird. Hier eine auto.arima
Demonstration, wie es mit auto.arima
im Prognosepaket funktioniert:
library(lineprof)
library(forecast)
l <- lineprof(auto.arima(AirPassengers))
shine(l)
Dadurch erhalten Sie eine glänzende App, mit der Sie tiefer in jeden Funktionsaufruf einsteigen können. So können Sie mit Leichtigkeit sehen, was dazu führt, dass Ihr R-Code langsamer wird. Unten sehen Sie einen Screenshot der glänzenden App:
Mikrobankmark
Mikrobankmarkierung ist nützlich, um die Zeit für ansonsten schnelle Verfahren abzuschätzen. Stellen Sie sich beispielsweise vor, wie viel Zeit benötigt wird, um Hallo Welt zu drucken.
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Dies liegt daran, dass system.time
im Wesentlichen eine Wrapper-Funktion für proc.time
, die in Sekunden misst. Da der Druck "Hallo Welt" weniger als eine Sekunde dauert, scheint die Zeit weniger als eine Sekunde zu sein, dies ist jedoch nicht der Fall. Um dies zu sehen, können wir das Paket microbenchmark verwenden:
library(microbenchmark)
microbenchmark(print("hello world"))
# Unit: microseconds
# expr min lq mean median uq max neval
# print("hello world") 26.336 29.984 44.11637 44.6835 45.415 158.824 100
Nachdem wir print("hello world")
100 Mal ausgeführt haben, betrug die durchschnittliche Zeit tatsächlich 44 Mikrosekunden. (Beachten Sie, dass beim Ausführen dieses Codes "Hallo Welt" 100 Mal auf die Konsole gedruckt wird.)
Wir können dies mit einem gleichwertigen Verfahren, cat("hello world\n")
, um zu sehen, ob es schneller ist als print("hello world")
:
microbenchmark(cat("hello world\n"))
# Unit: microseconds
# expr min lq mean median uq max neval
# cat("hello world\\n") 14.093 17.6975 23.73829 19.319 20.996 119.382 100
In diesem Fall ist cat()
fast doppelt so schnell wie print()
.
Alternativ können zwei Verfahren innerhalb desselben microbenchmark
Aufrufs verglichen werden:
microbenchmark(print("hello world"), cat("hello world\n"))
# Unit: microseconds
# expr min lq mean median uq max neval
# print("hello world") 29.122 31.654 39.64255 34.5275 38.852 192.779 100
# cat("hello world\\n") 9.381 12.356 13.83820 12.9930 13.715 52.564 100
Benchmarking mit Mikrobankmark
Sie können das microbenchmark
Paket verwenden, um ein "präzises Timing der Ausdrucksauswertung unter einer Millisekunde" durchzuführen.
In diesem Beispiel vergleichen wir die Geschwindigkeiten von sechs äquivalenten data.table
Ausdrücken zum Aktualisieren von Elementen in einer Gruppe basierend auf einer bestimmten Bedingung.
Genauer:
Eine
data.table
mit 3 Spalten:id
,time
undstatus
. Für jede ID möchte ich den Datensatz mit der maximalen Zeit suchen. Wenn für diesen Datensatz der Status true ist, möchte ich ihn auf false setzen, wenn die Zeit> 7 ist
library(microbenchmark)
library(data.table)
set.seed(20160723)
dt <- data.table(id = c(rep(seq(1:10000), each = 10)),
time = c(rep(seq(1:10000), 10)),
status = c(sample(c(TRUE, FALSE), 10000*10, replace = TRUE)))
setkey(dt, id, time) ## create copies of the data so the 'updates-by-reference' don't affect other expressions
dt1 <- copy(dt)
dt2 <- copy(dt)
dt3 <- copy(dt)
dt4 <- copy(dt)
dt5 <- copy(dt)
dt6 <- copy(dt)
microbenchmark(
expression_1 = {
dt1[ dt1[order(time), .I[.N], by = id]$V1, status := status * time < 7 ]
},
expression_2 = {
dt2[,status := c(.SD[-.N, status], .SD[.N, status * time > 7]), by = id]
},
expression_3 = {
dt3[dt3[,.N, by = id][,cumsum(N)], status := status * time > 7]
},
expression_4 = {
y <- dt4[,.SD[.N],by=id]
dt4[y, status := status & time > 7]
},
expression_5 = {
y <- dt5[, .SD[.N, .(time, status)], by = id][time > 7 & status]
dt5[y, status := FALSE]
},
expression_6 = {
dt6[ dt6[, .I == .I[which.max(time)], by = id]$V1 & time > 7, status := FALSE]
},
times = 10L ## specify the number of times each expression is evaluated
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# expression_1 11.646149 13.201670 16.808399 15.643384 18.78640 26.321346 10
# expression_2 8051.898126 8777.016935 9238.323459 8979.553856 9281.93377 12610.869058 10
# expression_3 3.208773 3.385841 4.207903 4.089515 4.70146 5.654702 10
# expression_4 15.758441 16.247833 20.677038 19.028982 21.04170 36.373153 10
# expression_5 7552.970295 8051.080753 8702.064620 8861.608629 9308.62842 9722.234921 10
# expression_6 18.403105 18.812785 22.427984 21.966764 24.66930 28.607064 10
Die Ausgabe zeigt, dass expression_3
in diesem Test der schnellste ist.
Verweise
data.table - Spalten hinzufügen und ändern
data.table - spezielle Gruppierungssymbole in data.table