我的system.time包装函数有问题吗?

时间:2011-02-28 13:08:46

标签: r

编辑:感谢@daroczig下面的可爱答案。然而,测试2仍然感觉它需要比测试1更长的时间,这是我想知道的。

更新:在第二次阅读时,@ daroczig的回答确实解释了我的困惑 - 问题是由于我没有正确地考虑system.time(expr)代码行。

我想制作一个system.time函数的版本,在理解运行时间波动方面,这对我自己来说会更具信息性:

system.time.summary <- function(N, expr) {
  t.mat <- replicate(N, system.time(expr))
  as.data.frame(apply(t.mat[1:3,], 1, summary))
}

然而问题是,在下面的自包含代码中,test.2 感觉test.1需要更长的时间(并且我已多次运行它们)检查),即使代码几乎完全相同(test.1使用包装函数,而test.2只是原始代码)

# set up number of runs
N <- 100

# test 1
system.time.summary(N, (1:1e8)^2 + 1)

        user.self sys.self elapsed
Min.        0.000    0.000   0.000
1st Qu.     0.000    0.000   0.000
Median      0.000    0.000   0.000
Mean        0.058    0.031   0.089
3rd Qu.     0.000    0.000   0.000
Max.        0.580    0.310   0.890

# test 2
t.mat = replicate(N, system.time((1:1e8)^2 + 1))
as.data.frame(apply(t.mat[1:3,], 1, summary))

        user.self sys.self elapsed
Min.        0.630    0.120   0.860
1st Qu.     0.665    0.170   0.880
Median      0.695    0.195   0.880
Mean        0.692    0.196   0.882
3rd Qu.     0.715    0.225   0.890
Max.        0.760    0.260   0.900

我希望我解释好了!它可能是目前的星期一早上,但这让我感到困惑......

我的系统:

# Windows Server 2008 R2
> sessionInfo()
R version 2.12.0 (2010-10-15)
Platform: x86_64-pc-mingw32/x64 (64-bit)

2 个答案:

答案 0 :(得分:7)

您在第一次测试中正在运行system.time(system.time()),并且在函数中使用system.time(1:1e8)^2 + 1)作为表达式并不是一个好主意,请参阅:

> expr <- system.time((1:1e8)^2 + 1)
> system.time(expr)
   user  system elapsed 
      0       0       0 

但无论如何:使用CRAN的microbenchmark包来达到这个目的,你不会后悔。设置您的独特功能,您可以轻松地推出100,1000或任何运行的模拟。您可以在基准测试结束时得到一个简洁的摘要和箱图。

例如:

> test1 <- function() (1:1e8)^2 + 1
> (results <- microbenchmark(test1(), times=10))
Unit: nanoeconds
               min         lq     median         uq        max
test1() 3565386356 3703142531 3856450582 3931033077 3986309085
> boxplot(results)

enter image description here

答案 1 :(得分:2)

正如daroczig所说,你有一个额外的system.time。但还有别的东西:

如果你在你的函数中添加browser(),你会看到会发生什么。事实上,你所做的表达式只被评估一次,然后保存在内存中。这就是R内部优化的方式。所以如果你这样做:

system.time.summary(N,(1:1e8)^2 +1)

t.mat在内部:

           [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
user.self  0.61    0    0    0    0    0    0    0    0     0
sys.self   0.36    0    0    0    0    0    0    0    0     0
elapsed    0.97    0    0    0    0    0    0    0    0     0
user.child   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
sys.child    NA   NA   NA   NA   NA   NA   NA   NA   NA    NA

和expr是:

Browse[2]> str(expr)
 num [1:100000000] 2 5 10 17 26 37 50 65 82 101 ...

改变它有点困难,因为R只会评估任何静态表达式一次,然后从内存中再检索99次结果。如果您不希望发生这种情况,则必须显式传递表达式,并添加eval()函数。 :

system.time.summary <- function(N, expr) {
  t.mat <- replicate(N, system.time(eval(expr)))
  as.data.frame(apply(t.mat[1:3,], 1, summary))
}

system.time.summary(N, expression((1:1e8)^2 + 1))

现在expr每次都会被评估,并且仍然是函数中的表达式:

Browse[2]> expr
expression((1:1e+08)^2 + 1)

这为您提供了正确的时间。

        user.self sys.self elapsed
Min.       0.6400   0.2000   0.970
1st Qu.    0.6850   0.2375   0.980
Median     0.7150   0.2700   0.985
Mean       0.7130   0.2700   0.985
3rd Qu.    0.7425   0.2975   0.990
Max.       0.7800   0.3500   1.000