R Language
Kodprofilering
Sök…
System tid
Systemtid ger dig den CPU-tid som krävs för att köra ett R-uttryck, till exempel:
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Du kan lägga till större kodstycken med hjälp av hängslen:
system.time({
library(numbers)
Primes(1,10^5)
})
Eller använd den för att testa funktioner:
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 ()
På sitt enklaste proc.time()
ger proc.time()
den totala förflutna CPU-tiden i sekunder för den aktuella processen. Att köra den i konsolen ger följande typ av utgång:
proc.time()
# user system elapsed
# 284.507 120.397 515029.305
Detta är särskilt användbart för att jämföra specifika kodrader. Till exempel:
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)
Detta ger följande utgång:
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()
är ett omslag för proc.time()
som returnerar den förflutna tiden för ett visst kommando / uttryck.
print(t1 <- system.time(replicate(1000,12^2)))
## user system elapsed
## 0.000 0.000 0.002
Observera att det returnerade objektet, klass proc.time
, är lite mer komplicerat än det ser ut på ytan:
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" ...
Linjeprofilering
Ett paket för linjeprofilering är lineprof som skrivs och underhålls av Hadley Wickham. Här är en snabb demonstration av hur det fungerar med auto.arima
i auto.arima
:
library(lineprof)
library(forecast)
l <- lineprof(auto.arima(AirPassengers))
shine(l)
Detta kommer att ge dig en blank app som gör att du kan gå djupare i varje funktionssamtal. Detta gör att du enkelt kan se vad som orsakar din R-kod att sakta ner. Det finns en skärmdump av den blanka appen nedan:
Microbenchmark
Microbenchmark är användbart för att uppskatta hur lång tid det tar för annars snabba procedurer. Överväga till exempel att uppskatta tiden det tar att skriva ut hejvärlden.
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
Detta beror på att system.time
huvudsak är en omslagsfunktion för proc.time
, som mäter på sekunder. Eftersom utskriften "hejvärld" tar mindre än en sekund verkar det som att tiden tar mindre än en sekund, men detta är inte sant. För att se detta kan vi använda paketets mikrobenchmark:
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
Här kan vi se efter att ha kört print("hello world")
100 gånger, den genomsnittliga tiden som tog var faktiskt 44 mikrosekunder. (Observera att körning av denna kod kommer att skriva ut "hej världen" 100 gånger på konsolen.)
Vi kan jämföra detta mot ett likvärdigt förfarande, cat("hello world\n")
, för att se om det är snabbare än 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
I detta fall är cat()
nästan dubbelt så snabb som print()
.
Alternativt kan man jämföra två procedurer inom samma microbenchmark
samtal:
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 med hjälp av mikrobenchmark
Du kan använda microbenchmark
för att utföra "exakt tidpunkt för uttrycksutvärdering under millisekund".
I detta exempel jämför vi hastigheterna för sex ekvivalenta data.table
uttryck för uppdatering av element i en grupp, baserat på ett visst villkor.
Mer specifikt:
En
data.table
med 3 kolumner:id
,time
ochstatus
. För varje id vill jag hitta posten med den maximala tiden - så om för den posten om statusen är sann, vill jag ställa in den till falsk om tiden är> 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
Utgången visar att i detta test är expression_3
det snabbaste.
referenser
data.table - Lägga till och ändra kolumner
data.table - speciella grupperingssymboler i data.table