何时使用缺失值与 NULL 值在 R 中传递未定义的函数参数,为啥?

Posted

技术标签:

【中文标题】何时使用缺失值与 NULL 值在 R 中传递未定义的函数参数,为啥?【英文标题】:When to use missing versus NULL values for passing undefined function arguments in R, and why?何时使用缺失值与 NULL 值在 R 中传递未定义的函数参数,为什么? 【发布时间】:2014-03-28 06:13:46 【问题描述】:

迄今为止,在编写 R 函数时,我传递了未定义的参数 作为 NULL 值,然后测试它们是否为 NULL,即

f1 <- function (x = NULL) 
   if(is.null(x))
      ...

但是我最近发现了将未定义的参数作为缺失传递的可能性,即

f2 <- function (x) 
   if(missing(x))
      ...

R 文档指出

目前缺少的只能用在直接正文中 定义参数的函数,而不是在 a 的主体中 嵌套函数或本地调用。这在未来可能会改变。

显然,这是使用缺失来确定未定义值的一个缺点,还有其他人或知道吗?或者用更有用的形式来表达这个问题“你什么时候使用缺失值和 NULL 值在 R 中传递未定义的函数参数,为什么?”

【问题讨论】:

我猜NULL 可能非常方便的情况是,函数中的参数可以被忽略或操纵长度 == 0。例如在f1 = function(x, y = NULL) c(x, y) 中,调用f1(3) 不会产生错误(就像NULL 不存在时一样)并且不需要额外检查。 【参考方案1】:

在我看来,missing 的限制何时适用尚不清楚。正如您所引用的,文档说缺少只能在函数的直接主体中使用。不过,一个简单的例子表明情况并非如此,当参数传递给嵌套函数时,它会按预期工作。

f1 = function(x, y, z)
  if(!missing(x))
    print(x)
  if(!missing(y))
    print(y)


f2 = function(x, y, z)
  if(!missing(z)) print(z)
  f1(x, y)

f1(y="2")
#> [1] "2"
f2(y="2", z="3")
#> [1] "3"
#> [1] "2"
f2(x="1", z="3")
#> [1] "3"
#> [1] "1"

我想看一个missing 在嵌套函数中不起作用的例子。

由reprex package (v0.2.1) 于 2019 年 9 月 30 日创建

【讨论】:

那条注释(在?missing 中)写于 2002 年。看起来这确实在过去 17 年的某个时候发生了变化,但文档没有。 或者引用是关于嵌套函数的,例如 f2 &lt;- function(z) f1 &lt;- function() if(missing(z)) cat("f1: z is missing\n") ; f1() 其中f2() 会产生错误。【参考方案2】:

NULL 只是您可以分配给变量的另一个值。它与您在函数声明中指定的任何其他默认值没有什么不同。

另一方面,

missing 检查用户是否提供了该参数,您可以默认赋值之前执行此操作 - 这要归功于 R 的惰性求值,只有在使用该变量时才会发生。 p>

你可以用这个实现的几个例子是:没有默认值的参数,你仍然可以省略 - 例如。 filetext 中的 read.table,或具有默认值的参数,您只能指定一个 - 例如nnmaxscan

通过浏览 R 代码,您会发现许多其他用例。

【讨论】:

在 R 3.0.2 中 text 似乎是 scan 中唯一没有默认值的参数。你知道这是否有特殊原因吗? 这是一个很好的答案,但您需要扩展它:当您有多个参数表示不同/冲突的模式或用例时(例如 @987654331 @ ) 并且您的默认活动必须在其中一种情况之间进行选择【参考方案3】:

missing(x) 似乎比使用默认 arg 到 x 等于 NULL 快一点。

> require('microbenchmark')
> f1 <- function(x=NULL) is.null(x)
> f2 <- function(x) missing(x)

> microbenchmark(f1(1), f2(1))
Unit: nanoseconds
  expr min  lq median    uq  max neval
 f1(1) 615 631  647.5 800.5 3024   100
 f2(1) 497 511  567.0 755.5 7916   100

> microbenchmark(f1(), f2())
Unit: nanoseconds
 expr min  lq median    uq  max neval
 f1() 589 619    627 745.5 3561   100
 f2() 437 448    463 479.0 2869   100

请注意,在f1 的情况下,如果您拨打f1()x 仍会报告为丢失,但它的值可以在f1 中读取。

第二种情况比第一种情况更普遍。 missing() 只是表示用户没有传递任何值。 is.null()(带有NULL 默认参数)表示用户要么没有传递任何东西,要么他/她传递了NULL

顺便说一下,plot.default()chisq.test() 使用 NULL 作为他们的第二个参数。另一方面,getS3method('t.test', 'default') 使用NULL 作为y 参数,使用missing() 作为mu(以便为许多使用场景做好准备)。

我认为一些 R 用户会更喜欢 f1 类型的函数,尤其是在使用 *apply 系列时:

sapply(list(1, NULL, 2, NULL), f1)

f2 的情况下实现这一点并不那么简单。

【讨论】:

我没有意识到在f1 的情况下,如果您拨打f1()x 仍会被报告为丢失。一般来说,设置默认值似乎是最有用的——它也让用户明确表示他们不必提供值。

以上是关于何时使用缺失值与 NULL 值在 R 中传递未定义的函数参数,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

传递给子组件的原始值在 Angular 2 的构造函数中未定义

UI路由器参数值在目标中未定义

使用 Context API 传递数据时值未定义

传递默认参数值与根本不传递参数?

SQL 空值

机器学习决策树(划分选择算法流程剪枝处理,连续值与缺失值处理)