R purrr:::pmap:如何按名称引用输入参数?

28

我正在使用R的purrr:::pmap函数,有三个输入。但不清楚在formula调用中如何显式地引用这些输入?当使用map2时,formula调用为~ .x + .y。但是在使用pmap时应该如何操作呢?

重新制作Hadley在http://r4ds.had.co.nz/lists.html中的示例。

library(purrr)
mu <- list(5, 10, -3)
sigma <- list(1, 5, 10)
n <- list(1, 3, 5)

args2 <- list(mean = mu, sd = sigma, n = n)
pmap(args2, rnorm)

如果我希望在调用rnorm函数时明确引用输入参数,我可以使用:

pmap(args2, function(mean, sd, n) rnorm(n, mean, sd))

但是如果我想使用公式方法进行此操作,该怎么做呢?例如,以下内容不起作用:

pmap(args2, ~rnorm(n=.n, mean=.mean, sd=.sd))

谢谢!!

3个回答

21

你可以使用with(...)来解决这个问题:

pmap(args2, ~with(list(...),rnorm(n, mean, sd)))
# [[1]]
# [1] 2.733528
# 
# [[2]]
# [1] 4.0967533 6.4926143 0.6083532
# 
# [[3]]
# [1]  1.8836592 -0.2090425 -4.0030168  1.1834931  3.2771316

更多解释请见:使用purrr::pmap利用.f列表名称


优雅的解决方案,不错! - Matifou

17

自从0.2.3版本以来,您可以使用..1..2..3等:

pmap(args2, ~ rnorm(..3, ..1, ..2))
但是...我已经在使用这个语法时遇到了麻烦,例如在使用replicate时:
pmap(list(1, 2), ~ replicate(n = ..1, expr = ..2))
# Error in FUN(X[[i]], ...) : the ... list does not contain 2 elements

可能是由于:

print(replicate)
# function (n, expr, simplify = "array") 
#   sapply(integer(n), eval.parent(substitute(function(...) expr)), 
#          simplify = simplify)

看起来在substitute()function(...) expr..2不协调,被解释为空的...的第二个元素。

请注意,pmap(list(1, 2), ~ replicate(n = ..1, expr = .y))仍然有效。


5

看起来在公式界面中,pmap无法通过名称访问列表中的参数。 您可以在https://github.com/hadley/purrr/issues/203上进行检查。

例如,您可以执行以下操作:

pmap(list(1:2, 5:6), ~ .x + .y)

因此,列表的第一个元素用.x表示,第二个用.y表示。然而,如果您尝试给列表的参数命名,就像下面这样:
pmap(list(a = 1:2, b =  5:6), ~ .a + .b)

那么你将会遇到这个错误:

Error in .f(a = .l[[c(1L, i)]], b = .l[[c(2L, i)]], ...) : 
  unused arguments (a = .l[[c(1, i)]], b = .l[[c(2, i)]])

我认为在函数

pmap 的公式界面中,如果您想使用公式界面而不使用 function(mean,sd,n),则最好的方法是:

  1. 不要命名列表的元素
  2. 不要使用超过两个参数(以使用隐式名称 .x 和 .y )

因此,您可以固定第三个参数 n 的值(例如 n = 4 ),然后运行:

<code><code>mu <- list(5, 10, -3)
sigma <- list(1, 5, 10)
set.seed(1)
pmap(list(mu,sigma), ~ rnorm(mean = .x, sd = .y, n = 4))
</code></code>

这将返回:

[[1]]
[1] 4.373546 5.183643 4.164371 6.595281

[[2]]
[1] 11.647539  5.897658 12.437145 13.691624

[[3]]
[1]  2.7578135 -6.0538839 12.1178117  0.8984324

[[4]]
[1]  9.136278  4.355900 14.374793 10.865199

1
非常感谢!特别高兴看到这个链接!不幸的是,在我的情况下,仅使用2个输入并不是真正的解决方案 :-( - Matifou
1
是的,我同意,只使用2个输入是较小的恶,但仍不令人满意。 至少您可以使用function(mean, sd, n)的方法;顺便问一下,您是否绝对想使用公式方法? - Etienne Kintzler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接