R Language
Profilage de code
Recherche…
Le temps du système
L'heure système vous donne le temps processeur requis pour exécuter une expression R, par exemple:
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Vous pouvez ajouter de plus gros morceaux de code en utilisant des accolades:
system.time({
library(numbers)
Primes(1,10^5)
})
Ou l'utiliser pour tester des fonctions:
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 ()
Dans sa forme la plus simple, proc.time()
donne le temps CPU total en secondes pour le processus en cours. L'exécuter dans la console donne le type de sortie suivant:
proc.time()
# user system elapsed
# 284.507 120.397 515029.305
Ceci est particulièrement utile pour évaluer des lignes de code spécifiques. Par exemple:
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)
Cela donne la sortie suivante:
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()
est un wrapper pour proc.time()
qui renvoie le temps écoulé pour une commande / expression particulière.
print(t1 <- system.time(replicate(1000,12^2)))
## user system elapsed
## 0.000 0.000 0.002
Notez que l'objet renvoyé, de classe proc.time
, est légèrement plus compliqué qu'il n'y paraît:
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" ...
Profilage de ligne
Un package de profilage de ligne est lineprof, écrit et géré par Hadley Wickham. Voici une démonstration rapide de son fonctionnement avec auto.arima
dans le package de prévisions:
library(lineprof)
library(forecast)
l <- lineprof(auto.arima(AirPassengers))
shine(l)
Cela vous fournira une application brillante, qui vous permettra d'approfondir chaque appel de fonction. Cela vous permet de voir facilement ce qui cause le ralentissement de votre code R. Il y a une capture d'écran de l'application brillante ci-dessous:
Microbenchmark
Microbenchmark est utile pour estimer le temps nécessaire à des procédures rapides. Par exemple, pensez à estimer le temps nécessaire pour imprimer hello world.
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
En effet, system.time
est essentiellement une fonction wrapper pour proc.time
, qui mesure en secondes. Comme l'impression de "hello world" prend moins d'une seconde, il semble que le temps pris soit inférieur à une seconde, mais ce n'est pas vrai. Pour voir cela, nous pouvons utiliser le microbenchmark du package:
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
Ici, on peut voir après avoir exécuté print("hello world")
100 fois, le temps moyen pris était en fait de 44 microsecondes. (Notez que l'exécution de ce code imprimera "Bonjour tout le monde" 100 fois sur la console.)
On peut comparer cela à une procédure équivalente, cat("hello world\n")
, pour voir s'il est plus rapide que 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
Dans ce cas, cat()
est presque deux fois plus rapide que print()
.
Alternativement, on peut comparer deux procédures dans le même appel de 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 en utilisant un microbenchmark
Vous pouvez utiliser le progiciel de microbenchmark
pour effectuer une évaluation précise de l'expression d'une durée inférieure à la milliseconde.
Dans cet exemple, nous comparons les vitesses de six expressions équivalentes data.table
pour mettre à jour des éléments dans un groupe, en fonction d'une certaine condition.
Plus précisement:
Une
data.table
avec 3 colonnes:id
,time
etstatus
. Pour chaque identifiant, je veux trouver l'enregistrement avec le temps maximum - alors si pour cet enregistrement si le statut est vrai, je veux le mettre à faux si le temps est> 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
La sortie montre que dans ce test, expression_3
est la plus rapide.
Les références
data.table - Ajout et modification de colonnes
data.table - symboles de regroupement spéciaux dans data.table