我倾向于使用管道操作符(%>%
,magrittr
或dplyr
库)。直到有一天,我试图在右侧使用system.time
命令。
system.time(mean(rnorm(1E7))) # ok
#### user system elapsed
#### 3.52 0.05 3.58
rnorm(1E7) %>% mean %>% system.time # ?
#### user system elapsed
#### 0 0 0
所以我去阅读文档,我尝试了这个(它说你可以通过将它括在括号中来强制评估RHS,但它给出了相同的行为:
rnorm(1E7) %>% mean %>% (function(x) system.time(x))
#### user system elapsed
#### 0 0 0
我的问题如下:
1。为什么命令system.time
在放置在管道末端时没有按预期工作?
2. 有没有办法测量由管道组成的一行代码的计算时间,而不必将整行放在括号内(这会扼杀管道的实际好处.. 。)或使用proc.time?
注意:与replicate
命令相同的问题。
答案 0 :(得分:14)
我能做的第二个好处是在system.time
上创建一个包装器,它接受一个未经评估的表达式并对其进行求值,然后你必须将大小写的表达式包装在大括号中并在管道时引用它,这样它就不会直到我的包装函数得到它的爪子时才进行评估:
> psystime = function(e){system.time(eval(e))}
> quote({rnorm(1e7) %>% mean}) %>% psystime
user system elapsed
0.764 0.004 0.767
>
我说第二好,因为最好的答案根本就是不要这样做。有时管道是问题,而不是解决方案。
另一种可能性是将您的管道表达式包装在引号中并将其提供给system.time
包装器,该包装器将其参数的计算版本作为文本运行:
> esystime = function(e){system.time(eval(parse(text=e)))}
> "rnorm(1e7) %>% mean" %>% esystime
user system elapsed
1.075 0.033 1.137
我猜这个用例实际上就是当你有一个很长的管道并希望快速查看运行需要多长时间时,所以你自然希望最后只是发送%>% system.time
。它可能同样容易,假设您知道“行首”和“行尾”的键盘快捷键,将system.time(
放在开头,)
放在最后。
答案 1 :(得分:0)
我想出了一个使用piping和proc.time的解决方法。它不是绝对完美但它可能会有所帮助。它还使用了发球台操作员。
首先定义一个Timer函数,用于计算全局环境中记录的start.time变量的时间。
Timer = function(x){
if (exists("start.time")){
print(proc.time() - start.time)
rm('start.time', envir=.GlobalEnv)
} else {
assign("start.time", proc.time(), envir=globalenv())
}
}
然后在管道的第二位使用它,并再次使用它:
diamonds %T>% Timer %>% group_by(clarity) %>% summarise(sd(price)) %>% Timer
#### user system elapsed
#### 0.02 0.00 0.02
除了第一个元素之外,你得到的所有东西的计算时间(但通常它只是数据,所以......)。我与system.time方式相比,它似乎没有给出很多不同的结果。