R Language
Codice di profilazione
Ricerca…
System.time
L'ora di sistema fornisce il tempo di CPU necessario per eseguire un'espressione R, ad esempio:
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Puoi aggiungere pezzi di codice più grandi attraverso l'uso di parentesi graffe:
system.time({
library(numbers)
Primes(1,10^5)
})
O usarlo per testare le funzioni:
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 ()
Nel modo più semplice, proc.time()
fornisce il tempo totale della CPU trascorso in secondi per il processo corrente. L'esecuzione in console dà il seguente tipo di output:
proc.time()
# user system elapsed
# 284.507 120.397 515029.305
Ciò è particolarmente utile per il benchmarking di linee di codice specifiche. Per esempio:
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)
Questo dà il seguente risultato:
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()
è un wrapper per proc.time()
che restituisce il tempo trascorso per un particolare comando / espressione.
print(t1 <- system.time(replicate(1000,12^2)))
## user system elapsed
## 0.000 0.000 0.002
Si noti che l'oggetto restituito, di classe proc.time
, è leggermente più complicato di quanto appaia sulla superficie:
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" ...
Line Profiling
Un pacchetto per il profiling di linea è lineprof che è scritto e mantenuto da Hadley Wickham. Ecco una rapida dimostrazione di come funziona con auto.arima
nel pacchetto di previsione:
library(lineprof)
library(forecast)
l <- lineprof(auto.arima(AirPassengers))
shine(l)
Questo ti fornirà un'app lucida, che ti permetterà di approfondire ogni chiamata di funzione. Ciò consente di vedere con facilità ciò che sta causando il rallentamento del codice R. Di seguito è disponibile uno screenshot dell'app lucida:
microbenchmark
Microbenchmark è utile per stimare il tempo necessario per procedure altrimenti veloci. Ad esempio, considera la stima del tempo impiegato per stampare Hello World.
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Questo perché system.time
è essenzialmente una funzione wrapper per proc.time
, che misura in secondi. Poiché la stampa di "Ciao mondo" richiede meno di un secondo, sembra che il tempo impiegato sia inferiore a un secondo, tuttavia questo non è vero. Per vedere questo possiamo usare il pacchetto microbenchmark:
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
Qui possiamo vedere dopo aver eseguito la print("hello world")
100 volte, il tempo medio impiegato era di 44 microsecondi. (Si noti che l'esecuzione di questo codice stamperà "Hello World" 100 volte sulla console.)
Possiamo confrontarlo con una procedura equivalente, cat("hello world\n")
, per vedere se è più veloce della 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 questo caso, cat()
una velocità quasi doppia rispetto a print()
.
In alternativa si possono confrontare due procedure all'interno della stessa chiamata microbenchmark
:
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 utilizzando microbenchmark
È possibile utilizzare il pacchetto microbenchmark
per condurre "tempi di misurazione dell'espressione al millisecondo precisi".
In questo esempio stiamo confrontando le velocità di sei espressioni data.table
equivalenti per l'aggiornamento di elementi in un gruppo, in base a una determinata condizione.
Più specificamente:
Un
data.table
con 3 colonne:id
,time
estatus
. Per ogni id, voglio trovare il record con il tempo massimo - quindi se per quel record se lo stato è vero, voglio impostarlo su false se il tempo è> 7
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
L'output mostra che in questo test expression_3
è il più veloce.
Riferimenti
data.table - Aggiunta e modifica di colonne
data.table - simboli di raggruppamento speciali in data.table