R Language
コードプロファイリング
サーチ…
システム時刻
システム時刻は、R式を実行するために必要なCPU時間を示します。たとえば、次のようになります。
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
中括弧を使用して、より大きなコードを追加することができます。
system.time({
library(numbers)
Primes(1,10^5)
})
または、関数をテストするために使用します。
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()
最も簡単な場合、 proc.time()
は、現在のプロセスの合計CPU時間を秒単位でproc.time()
ます。コンソールで実行すると、次のような出力が得られます。
proc.time()
# user system elapsed
# 284.507 120.397 515029.305
これは、特定のコード行をベンチマークする場合に特に便利です。例えば:
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)
これにより、次の出力が得られます。
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()
は、特定のコマンド/式の経過時間を返すproc.time()
ラッパーです。
print(t1 <- system.time(replicate(1000,12^2)))
## user system elapsed
## 0.000 0.000 0.002
クラスproc.time
返されるオブジェクトは、サーフェスに表示されるよりもやや複雑です。
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" ...
ラインプロファイリング
ラインプロファイリングのための1つのパッケージは、Hadley Wickhamによって書かれ維持されているlineprofです。予測パッケージのauto.arima
でどのように動作するかを簡単に説明します。
library(lineprof)
library(forecast)
l <- lineprof(auto.arima(AirPassengers))
shine(l)
これは光るアプリを提供します。これにより、すべての関数呼び出しを深く掘り下げることができます。これにより、Rコードが遅くなっている原因を簡単に確認することができます。以下のような光沢のあるアプリのスクリーンショットがあります:
マイクロベンチマーク
Microbenchmarkは、その他の高速手順では時間の見積もりに役立ちます。たとえば、こんにちは世界を印刷するのにかかる時間を見積もることを検討してください。
system.time(print("hello world"))
# [1] "hello world"
# user system elapsed
# 0 0 0
これは、 system.time
が本質的にproc.time
ラッパー関数でproc.time
、秒単位で測定されるためproc.time
。 "hello world"の印刷には1秒もかかりませんので、撮影時間は1秒未満ですが、これは当てはまりません。これを見るために、パッケージのマイクロベンチマークを使用することができます:
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
ここでprint("hello world")
100回実行した後、平均して44マイクロ秒であった。 (このコードを実行すると "hello world"がコンソールに100回印刷されることに注意してください)。
これを同等の手続きcat("hello world\n")
と比較して、 print("hello world")
より高速かどうかを調べることができ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
この場合、 cat()
はprint()
ほぼ2倍の速さです。
あるいは、同じmicrobenchmark
コール内の2つの手順を比較することもできます。
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
マイクロベンチマークを使用したベンチマーク
microbenchmark
パッケージを使用して、「ミリ秒以下の正確な式評価のタイミング」を実行できます。
この例では、特定の条件に基づいて、グループ内の要素を更新するための6つの同等のdata.table
式の速度を比較しています。
すなわち:
id
、time
、status
3列のdata.table
。各idに対して、最大時間のレコードを検索したい - ステータスがtrueならそのレコードのために時間が7より大きい場合はfalseに設定したい
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
出力は、このテストではexpression_3
が最も速いことを示しています。
参考文献
data.table - data.tableの特殊なグループ化シンボル