2014-12-03 27 views
6

我有一些R代码里面:R的system.time如何工作?

time.read = system.time(df <- data.frame(fread(f))) 
print(class(time.read)) 
#[1] "proc_time" 
print(class(df)) 
#[1] "data.frame" 

不知何故当这被执行,在主要研发环境/范围:

  • time.read具有值
  • DF存在并包含正确data.frame

我认为在函数内部创建的变量在函数范围之外是不可用的吗?这个怎么用?为什么在运行以下命令后,主R环境中不存在?

fx <- function(z){return(1)} 
out = fx(y <- 300) 
print(out) 
#[1] 1 
print(y) 
#Error in print(y) : object 'y' not found 

谢谢!

回答

18

伟大的问题! R做了一些与其论证特有的东西,这会导致很多混淆,但也非常有用。

当您将参数传递给R函数时,直到 它才在函数内部实际使用。在此之前,参数在 附近的一个称为promise的特殊容器中。承诺持有 表达式和他们应该被评估的环境 - 对于 参数,这是调用者的环境。

但是,只要你使用函数内部的参数,它的值是 计算。这就是system.time的工作原理。简化:

system.time = function (expr) { 
    before = proc.time() 
    expr 
    proc.time() - before 
} 

换句话说,功能简单的记录时间看其 参数之前。 然后它查看它的参数并因此引起它的评估,然后它记录经过的时间。但请记住, 参数的评估发生在调用者的范围内,因此在您的情况下, 指定的目标(df)也在父范围内可见。

在第二个示例中,函数fx从不查看其参数,因此它永远不会被评估。您可以轻松地改变这种状况,迫使其 参数的评价,简单地使用它:

fx <- function(z) { 
    z 
    return(1) 
} 

实际上,R有一个特殊的功能 - force为了这个目的:

fx <- function(z) { 
    force(z) 
    return(1) 
} 

force是简单的语法糖,它的定义很简单,就是返回 它的参数:

force = function (x) x 

事实上, R不直接评估其参数是有用的,因为 也可以检索函数内的未评估形式。这被称为 non-standard evaluation,并且它有时用于评价在不同范围(使用eval功能与指定其 参数envir)的 表达,或检索关于未计算的,表达 信息。

许多功能使用,最突出plot,其中猜测基础上绘制的变量/表达式默认 轴标签:

x = seq(0, 2 * pi, length.out = 100) 
plot(x, sin(x)) 

现在轴标签是xsin(x)。该plot函数知道这一点,因为 它里面,它可以看看它的功能参数未计算的表达式:

xlabel = deparse(substitute(x)) 
ylabel = deparse(substitute(y)) 

substitute检索未计算的表达式。 deparse将其转换为字符串表示形式。

+1

好的答案,除了'system.time'实际上并没有使用'eval'(至少不是在我的R版本中)。它直接评估promise表达式,甚至不使用'force',就像在第二个版本的'fx'中一样。 – mrip 2014-12-03 12:50:43

+0

@mrip是的,我有一半的想法来重写我的答案,因为我的简化实际上使它更复杂。在R中,*每个*函数参数都是一个承诺,非标准评估就是这样一个特殊情况,即用户不立即评估函数参数,而是替换它。 – 2014-12-03 13:01:47

+0

@mrip从头开始,我完全重写了答案。你怎么看?现在更为正确,但它仍然可以理解吗? – 2014-12-03 13:25:34