R Language
Code profilering
Zoeken…
Systeemtijd
Systeemtijd geeft u de CPU-tijd die nodig is om een R-expressie uit te voeren, bijvoorbeeld:
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
U kunt grotere stukjes code toevoegen met behulp van accolades:
system.time({
library(numbers)
Primes(1,10^5)
})
Of gebruik het om functies te testen:
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 ()
Op zijn eenvoudigst geeft proc.time()
de totale verstreken CPU-tijd in seconden voor het huidige proces. Het uitvoeren van het in de console geeft het volgende type uitvoer:
proc.time()
# user system elapsed
# 284.507 120.397 515029.305
Dit is met name handig voor het benchmarken van specifieke coderegels. Bijvoorbeeld:
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)
Dit geeft de volgende output:
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()
is een wrapper voor proc.time()
die de verstreken tijd voor een bepaalde opdracht / uitdrukking retourneert.
print(t1 <- system.time(replicate(1000,12^2)))
## user system elapsed
## 0.000 0.000 0.002
Merk op dat het geretourneerde object, van klasse proc.time
, iets gecompliceerder is dan het op het oppervlak lijkt:
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" ...
Lijnprofilering
Een pakket voor lijnprofilering is lineprof die is geschreven en wordt onderhouden door Hadley Wickham. Hier is een korte demonstratie van hoe het werkt met auto.arima
in het voorspellingspakket:
library(lineprof)
library(forecast)
l <- lineprof(auto.arima(AirPassengers))
shine(l)
Dit zal u voorzien van een glanzende app, waarmee u dieper in elke functieaanroep kunt ingaan. Hierdoor kunt u gemakkelijk zien wat uw R-code vertraagt. Er is een screenshot van de glanzende app hieronder:
Microbenchmark
Microbenchmark is handig voor het schatten van de tijd die nodig is voor anders snelle procedures. Overweeg bijvoorbeeld om een schatting te maken van de tijd die nodig is om hallo wereld af te drukken.
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Dit komt omdat system.time
in wezen een system.time
is voor proc.time
, die in seconden meet. Omdat het afdrukken van "hallo wereld" minder dan een seconde kost, lijkt het erop dat de benodigde tijd minder dan een seconde is, maar dit is niet waar. Om dit te zien kunnen we het pakket microbenchmark gebruiken:
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
Hier kunnen we na het uitvoeren van print("hello world")
100 keer zien, de gemiddelde tijd die het kostte was in feite 44 microseconden. (Merk op dat het uitvoeren van deze code 100 keer "hallo wereld" op de console afdrukt.)
We kunnen dit vergelijken met een vergelijkbare procedure, cat("hello world\n")
, om te zien of het sneller is dan 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 dit geval is cat()
bijna twee keer zo snel als print()
.
Als alternatief kan men twee procedures binnen dezelfde microbenchmark
oproep vergelijken:
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 met behulp van microbenchmark
U kunt het microbenchmark
pakket gebruiken om "sub-milliseconden nauwkeurige timing van expressie-evaluatie" uit te voeren.
In dit voorbeeld vergelijken we de snelheden van zes equivalente data.table
expressies voor het bijwerken van elementen in een groep, op basis van een bepaalde voorwaarde.
Specifieker:
Een
data.table
met 3 kolommen:id
,time
enstatus
. Voor elke id wil ik het record met de maximale tijd vinden - en als voor dat record als de status waar is, wil ik het op onwaar zetten als de tijd> 7 is
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
De output laat zien dat in deze test expression_3
het snelst is.
Referenties
data.table - kolommen toevoegen en wijzigen
data.table - speciale groeperingssymbolen in data.table