r - 为什么 `missing` 和默认参数在 `lapply` 调用的函数中不起作用?

标签 r lapply

令我惊讶的是,missing 似乎无法在 lapply 调用的函数中工作。假设我有以下功能:

.add <- function(x, arg, ...) {
  if (missing(arg)) {
    arg <- 1
  }
  print(match.call())
  return(x + arg)
}

wrapper <- function(l, arg, ...) {
  return(lapply(l, .add, arg=arg, ...))
}

设置 arg 显式工作方式类似于异常(exception):

wrapper(list(x=1:10, y=1:10), arg=1)
#FUN(x = X[[1L]], arg = ..1)
#FUN(x = X[[2L]], arg = ..1)
#$x
# [1]  2  3  4  5  6  7  8  9 10 11
#
#$y
# [1]  2  3  4  5  6  7  8  9 10 11

如果没有arg,我希望得到相同的输出,但它失败了:

wrapper(list(x=1:10, y=1:10))
#FUN(x = X[[1L]], arg = ..1)
# Error in FUN(X[[1L]], ...) : argument "arg" is missing, with no default

missing 适用于未使用 lapply 的嵌套包装函数。 为什么它在lapply调用的函数中似乎没有效果?

编辑:默认参数也不起作用:

.add <- function(x, arg=5, ...) {
  if (missing(arg)) {
    arg <- 1
  }
  print(match.call())
  return(x + arg)
}

wrapper(list(x=1:10, y=1:10))
#FUN(x = X[[1L]], arg = ..1)
# Error in FUN(X[[1L]], ...) : argument "arg" is missing, with no default

看来 arg 既不缺失,也不可访问。这里会发生什么?

(我知道我可以通过在 wrapper 中设置 arg=NULLif (is.null(arg)) 来规避这个问题.add 或其他东西。.add 是一个内部函数,它根据输入自行确定 arg (例如 arg= mean(x)),我希望包装器中的 arg 为用户记录参数 arg 并允许用户覆盖默认行为。最重要的是:我想了解为什么这不起作用!)

EDIT2:终于修复了此行为。这是 R < 3.2.0 中的一个错误,请参阅 PR#15707 .

最佳答案

首先,我要提到的是,我认为执行此操作的惯用方法是构建一个调用,然后对其进行评估。有关示例,请参阅write.csv。我相信这段代码会使用该方法完成您想要的事情。

wrapper <- function(X, arg, ...) {
  force(X) # optional; if X is missing, the error message will be more informative
  Call <- match.call(expand.dots=TRUE)
  Call[[1L]] <- as.name("lapply")
  Call$FUN <- as.name(".add")
  eval.parent(Call)
}

好的,现在尝试解释您发现的问题。我也准备好接受纠正,但希望这至少有助于澄清问题,就像 @idfah 的回答一样。

首先,我将解决“默认”问题,因为我认为它更简单。我认为这个可以变得更简单,如以下两个函数所示,其中第二个 (f2) 只需调用第一个 (f1)。我们看到的是,f1 中的默认参数被 f2 中的 x 的 promise 覆盖,并且当评估该 promise 时,它是丢失的。这个故事的寓意(我认为);如果该变量包含在调用中,则必须在调用函数中再次设置默认值。

f1 <- function(x=1) {print(match.call()); x}
f2 <- function(x) {f1(x=x)}
f1()
## f1()
## [1] 1
f2()
## f1(x = x)
## Error in f1(x = x) : argument "x" is missing, with no default

现在讨论 lapply 问题中缺失的问题。这里我基本上有 sgibb 的代码,但添加了一条关于 arg 是否被认为丢失的消息。我们遇到了一个似乎很奇怪的矛盾;该消息告诉我们 arg 没有丢失,但是当函数尝试访问它时,我们收到一条错误消息,告诉我们 arg 丢失了。

.add <- function(x, arg) {
  print(match.call())
  if(missing(arg)) {
    message("arg is missing in .add")
    x
  } else {
    message("arg is not missing")
    x + arg
  }
}
wrapper <- function(l, arg) {lapply(l, .add, arg=arg)}
wrapper(1)
## FUN(x = 1[[1L]], arg = ..1)
## arg is not missing
## Error in FUN(1[[1L]], ...) : argument "arg" is missing, with no default

我认为正在发生的事情是lapply将 promise 放入..1中的arg,所以它看起来并没有丢失,但是当它尝试评估它时,它发现它丢失了。这个故事的寓意(我认为);不要尝试通过 lapply 传播缺失值。

更新:更准确地说,这与点扩展的工作原理有关。考虑这个版本的lapply(它实际上不适用于列表,但在其他方面具有相同的代码风格);这表明我们得到了相同的行为。

apply3 <- function(X, FUN, ...) { 
  print(match.call())
  FUN(X, ...)
}
wrapper3 <- function(l, arg) {apply3(l, .add, arg=arg)}
wrapper3(1)
## apply3(X = l, FUN = .add, arg = arg)
## FUN(x = X, arg = ..1)
## arg is not missing
## Error in FUN(X, ...) : argument "arg" is missing, with no default

但是当我们用变量名称替换点时,它会按预期工作。

apply4 <- function(X, FUN, hm) { 
  print(match.call())
  FUN(X, hm)
}
wrapper4 <- function(l, arg) {apply4(l, .add, hm=arg)}
wrapper4(1)
## apply4(X = l, FUN = .add, hm = arg)
## FUN(x = X, arg = hm)
## arg is missing in .add
## [1] 1

还有一个例子;如果我使用点,但自己进行扩展,通过直接调用 ..1 ,它也可以工作!这很奇怪,因为匹配的调用与不起作用的版本相同。

apply3b <- function(X, FUN, ...) { 
  print(match.call())
  FUN(X, ..1)
}
wrapper3b <- function(l, arg) {apply3b(l, .add, arg=arg)}
wrapper3b(1)
## apply3b(X = l, FUN = .add, arg = arg)
## FUN(x = X, arg = ..1)
## arg is missing in .add
## [1] 1

关于r - 为什么 `missing` 和默认参数在 `lapply` 调用的函数中不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18136720/

相关文章:

用另一个变量的值替换一个变量中的 NA

回归模型作为数据表中的列,R

R lapply() : Change all columns within all data frames in a list to numeric, 然后将所有值转换为百分比

r - 按几列对data.table进行分组时如何在输出中保留列

python - 我可以使用 rpy2 将 Pandas 数据帧保存到 .Rdata 文件吗?

r - 使用传单和 R 为 CircleMarkers 添加边框

R按文件大小排序列表

r - 使用 ddply 和 lapply 聚合包含 NA 的类别?

r - 批量为变量分配名称时,R Functionals不起作用

macos - Mac Lion 上的 PLR 安装