コードが遅い!

効率的なRコードの書き方

Colin Gillespie

Jumping Rivers & Newcastle University

コードは本当に遅い?

  • 1秒?
  • 1分?
  • 1時間?
効率的なRコードの書き方

コードは本当に遅い?

効率的なRコードの書き方

ベンチマーク

  1. ベンチマーク対象の機能を関数でラップします。
  2. 異なるシナリオ(例:データセット)で関数の時間を計測します。
効率的なRコードの書き方

例:数列の生成

$$ 1, 2, 3, \ldots, n $$

オプション 1
1:n
オプション 2
seq(1, n)
オプション 3
seq(1, n, by = 1)
効率的なRコードの書き方

関数のラッピング

colon <- function(n) 1:n
colon(5)
1 2 3 4 5
seq_default <- function(n) seq(1, n)
seq_by <- function(n) seq(1, n, by = 1)
効率的なRコードの書き方

system.time() による計測

system.time(colon(1e8))
#   user  system elapsed
#  0.032   0.028   0.060
system.time(seq_default(1e8))
#   user  system elapsed
#  0.060   0.028   0.086
system.time(seq_by(1e8))
#   user  system elapsed
#  1.088   0.520   1.600
  • user 時間:ユーザー命令の実行に使用されたCPU時間。
    • system 時間:システムが呼び出し元プロセスの代わりに実行したCPU時間。
    • elapsed 時間:userとsystemのほぼ合計。通常はこの値を重視します。
効率的なRコードの書き方

結果の保存

以下のコードは結果を保存しません。

system.time(colon(1e8))

結果を保存するには、再実行が必要です。

res <- colon(1e8)

<- 演算子は以下の両方を実行します:

  • 引数の渡し
  • オブジェクトの代入
system.time(res <- colon(1e8))

= 演算子は以下のいずれかを実行します:

  • 引数の渡し
  • オブジェクトの代入
# Raises an error
system.time(res = colon(1e8))
効率的なRコードの書き方

相対時間

メソッド 絶対時間(秒) 相対時間
colon(n) 0.060 $0.060/0.060 = 1.00$
seq_default(n) 0.086 $0.086/0.060 = 1.40$
seq_by(n) 1.607 $1.60/0.060 = 26.7$
効率的なRコードの書き方

microbenchmark パッケージ

  • 関数を比較する
    • 各関数を複数回実行する
library("microbenchmark")

n <- 1e8 microbenchmark(colon(n), seq_default(n), seq_by(n), times = 10) # Run each function 10 times
# Unit: milliseconds
#           expr  min   lq  mean  median   uq  max neval cld
#       colon(n)   59  130   220     202  341  391    10  a
# seq_default(n)   94  204   290     337  348  383    10  a
#      seq_by(n) 1945 2044  2260    2275 2359 2787    10   b
効率的なRコードの書き方

練習しましょう!

効率的なRコードの書き方

Preparing Video For Download...