何时使用缺失值与 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 <- function(z) f1 <- function() if(missing(z)) cat("f1: z is missing\n") ; f1()
其中f2()
会产生错误。【参考方案2】:
NULL
只是您可以分配给变量的另一个值。它与您在函数声明中指定的任何其他默认值没有什么不同。
missing
检查用户是否提供了该参数,您可以在默认赋值之前执行此操作 - 这要归功于 R 的惰性求值,只有在使用该变量时才会发生。 p>
你可以用这个实现的几个例子是:没有默认值的参数,你仍然可以省略 - 例如。 file
和 text
中的 read.table
,或具有默认值的参数,您只能指定一个 - 例如n
和 nmax
在scan
。
通过浏览 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 中传递未定义的函数参数,为啥?的主要内容,如果未能解决你的问题,请参考以下文章