2

離散イベント シミュレーションにいくつかのルールしかない場合、これは重要ではありませんが、多数のルールがあり、それらが互いに干渉する可能性がある場合は、それらが「どの」「どこで」使用されているかを追跡する必要があります。

  • 以下のコードを元の関数と同じくらい速く取得する方法を知っている人はいますか?
  • よりも優れたオプションはありますeval(parse(...)か?

これは、速度が 100 倍低下することを示す簡単な例です。シミュレーションを実行し、(多数のルールのうちの) 1 つが次のとおりであると仮定します。時間が 5 未満の状態を選択します。

> a <- rnorm(100, 50, 10)
> print(summary(microbenchmark::microbenchmark(a[a < 5], times = 1000L, unit = "us")))
   expr  min   lq     mean median   uq    max neval
a[a < 5] 0.76 1.14 1.266745  1.141 1.52 11.404  1000

myfun <- function(a0) {
  return(eval(parse(text = myrule)))
}

> myrule <- "a < a0" # The rule could be read from a file.
print(summary(microbenchmark::microbenchmark(a[myfun(5)], times = 1000L, unit = "us")))
    expr    min      lq     mean  median      uq     max neval
a[myfun(5)] 137.61 140.271 145.6047 141.411 142.932 343.644  1000

注:ブックキーピングを効率的に行うことができる追加のrete パッケージは必要ないと思います。でも、違う意見があれば教えて...

4

1 に答える 1

2

これをプロファイリングしましょう:

Rprof()
for (i in 1:1e4) a[myfun(5)]
Rprof(NULL)
summaryRprof()

#$by.self
#             self.time self.pct total.time total.pct
#"parse"           0.36    69.23       0.48     92.31
#"structure"       0.04     7.69       0.06     11.54
#"myfun"           0.02     3.85       0.52    100.00
#"eval"            0.02     3.85       0.50     96.15
#"stopifnot"       0.02     3.85       0.06     11.54
#"%in%"            0.02     3.85       0.02      3.85
#"anyNA"           0.02     3.85       0.02      3.85
#"sys.parent"      0.02     3.85       0.02      3.85
#
#$by.total
#               total.time total.pct self.time self.pct
#"myfun"              0.52    100.00      0.02     3.85
#"eval"               0.50     96.15      0.02     3.85
#"parse"              0.48     92.31      0.36    69.23
#"srcfilecopy"        0.12     23.08      0.00     0.00
#"structure"          0.06     11.54      0.04     7.69
#"stopifnot"          0.06     11.54      0.02     3.85
#".POSIXct"           0.06     11.54      0.00     0.00
#"Sys.time"           0.06     11.54      0.00     0.00
#"%in%"               0.02      3.85      0.02     3.85
#"anyNA"              0.02      3.85      0.02     3.85
#"sys.parent"         0.02      3.85      0.02     3.85
#"match.call"         0.02      3.85      0.00     0.00
#"sys.function"       0.02      3.85      0.00     0.00

ほとんどの時間は で費やされparseます。これはベンチマークで確認できます。

microbenchmark(a[myfun(5)], times = 1000L, unit = "us")
#Unit: microseconds
#        expr    min     lq     mean median     uq     max neval
# a[myfun(5)] 67.347 69.141 72.12806 69.909 70.933 160.303  1000

a0 <- 5
microbenchmark(parse(text = myrule), times = 1000L, unit = "us")
#Unit: microseconds
#                 expr    min     lq     mean median     uq     max neval
# parse(text = myrule) 62.483 64.275 64.99432 64.787 65.299 132.903  1000

ルールをファイルからテキストとして読み取ることが難しい要件である場合、これを高速化する方法はないと思います。もちろん、同じルールを繰り返し解析するべきではありませんが、ここではそれを想定しています。

詳細な説明を提供するコメントに応じて編集します。

ルールは引用符で囲まれた式として保存する必要があります (たとえば、saveRDSファイルとして必要な場合はリストに使用します)。

myrule1 <- quote(a < a0)
myfun1 <- function(rule, a, a0) {eval(rule)}

microbenchmark(a[myfun1(myrule1, a, 30)], times = 1000L, unit = "us")
#Unit: microseconds
#                      expr   min    lq     mean median    uq    max neval
# a[myfun1(myrule1, a, 30)] 1.792 2.049 2.286815  2.304 2.305 30.217  1000

便宜上、その式のリストを S3 オブジェクトにしprintて、より良い概要を得るために適切なメソッドを作成することができます。

于 2016-06-15T07:07:42.987 に答える