微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

什么时候 mapply 的 MoreArgs 参数不能被 R 的向量回收规则取代?

如何解决什么时候 mapply 的 MoreArgs 参数不能被 R 的向量回收规则取代?

我试图想出一个例子来说明 mapplyMoreArgs 参数何时有用。我已经被彻底打败了。令人愤慨的是,即使 mapply 的文档中给出的例子也是不够的。文档将 mapply(rep,times = 1:4,MoreArgs = list(x = 42)) 作为他们使用 MoreArgs 的唯一示例,但我发现 R 的向量回收规则意味着 mapply(rep,42) 给出完全相同的输出

那么什么时候可以不通过删除相应的 MoreArgs 包装器来替换 MoreArgs = list(...)?我试图自己想出一些例子,但每次都失败了。例如,mapply(rnorm,1:10,11:20,MoreArgs = list(5),SIMPLIFY = FALSE)mapply(rnorm,5,SIMPLIFY = FALSE) 相同。

评论的引导下,I've also tried 示例中我们需要为每次调用 mapply函数调用回收一个向量。但是,似乎 mapply 在使用包含所述向量的列表之间的功能上没有区别 - 例如list(c(0.6,0.3,0.1)) - 作为 ... 参数或作为 MoreArgs 参数。在 MoreArgs 的情况下,列表的内容按预期回收,在 ... 的情况下,向量回收规则意味着列表的内容将在每种情况下回收,提供相同的功能MoreArgs。这让我回到最初的问题:什么时候可以使用 MoreArgsmapply 参数来提供无法从 ... 参数和向量回收规则中获得的功能?我还没有看到通过简单地删除 MoreArgs= 参数并将相关部分传递给 ... 无法获得相同功能的情况。

解决方法

如果我们要传递命名参数,则可以在 MoreArgs 中传递 list。有时,参数取决于函数中参数的顺序,并按该顺序进行计算。例如如果我们想要指定参数 n

mapply(rnorm,1:10,11:20,MoreArgs = list(n = 5),SIMPLIFY = FALSE)

即使没有 MoreArgs 它也能工作,因为它为每个传递的元素进行回收。但是,在 MoreArgs 中传递参数有助于区分函数参数和 mapply/Map 的输入。当我们调用没有 lambda/匿名函数的函数时,通常会使用这些函数,因为它也可以写成

mapply(function(x,y) rnorm(n = 5,mean = x,sd = y),SIMPLIFY = FALSE)

请注意,下面的失败是因为没有 mapply 的输入,只有函数参数输入

mapply(rnorm,MoreArgs = list(n = 5,mean = 1:10,sd = 11:20))

当我们按照 OP 帖子中指定的顺序传递参数而没有名称时,假设 n 是 5,它不会被视为 5,而是现在是 sd,因为rnorm 的顺序是 nmeansd,如 Usage

?rnorm 所示

rnorm(n,mean = 0,sd = 1)

mapply(rnorm,5,SIMPLIFY = FALSE)

对比一下

mapply(rnorm,SIMPLIFY = FALSE)

mapply(rnorm,n = 5,SIMPLIFY = FALSE)

可以用 MoreArgs 写成,也可以用第一个语法显示

,

更新:我开始相信这个答案是不正确的。我在下面大胆的担忧似乎是正确的,使这个答案的关键部分无效。如需正确答案,请参阅我的另一个答案。

根据评论中Henrik的引导,我们可以给出答案。 MoreArgs 最适合用于您想要回收的参数,但不是 Mapply 想要的方式。当所述参数是向量或列表时,通常就是这种情况。下面是一个扩展示例。

考虑 rmultinom 函数。它的行为非常糟糕。它需要 3 个参数:n 控制要取的样本数量,size 控制每个样本的大小,以及概率向量 prob,其中向量中的每个概率可以看作length(prob) 边的有偏骰子滚动与所讨论的 prob 中的条目相对应的面的机会。它的输出是一个向量,显示偏置芯片落在每一侧的次数。例如,这是一种可能的输入和输出(从上到下读取,而不是从左到右):

 rmultinom(3,10,c(0.6,0.3,0.1))
     [,1] [,2] [,3]
[1,]    6    6    6
[2,]    2    2    4
[3,]    2    2    0

为什么我说 rmultinom 行为不端?因为这也是有效的:

rmultinom(3,c(0.6))
     [,]   10   10   10

您可能认为为 rmultinom 提供一个总和不为 1 的概率向量会引发错误,但出于我不认为理解的技术原因,事实并非如此。

>

那么让我们回到mapply。假设我想用 n 作为 3、4 和 5 进行测试,第一次测试为 10,第二次测试为 11,最后一次测试为 12。我希望 size 固定在 prob。如果我最后一点弄错了,那么我们就会得到之前的不良行为。

让我们从尝试 c(0.6,0.1) 开始:

mapply(rmultinom,3:5,10:12,0.1))

那没有用。我可以告诉你,使用 mapply(rmultinom,0.1)) [[1]] [,] 10 10 10 [[2]] [,3] [,4] [1,] 11 11 11 11 [[3]] [,4] [,5] [1,] 12 12 12 12 12 作为我们的最后一个参数也不起作用。它给出了完全相同的输出,所以我什至不会展示它。忘记 list(0.6,0.1)c 直接使用 list 怎么样?

0.6,0.1

没有运气。由于 mapply(rmultinom,0.6,0.1) Error in (function (n,size,prob) : unused arguments (dots[[4]][[1]],dots[[5]][[1]]) 的工作方式,我无法判断是向量回收规则还是 rmultinom 背叛了我们,但我想不出任何明智的方法来使用我们尚未使用的回收规则试过了。那么如何将 mapply 与我们的原始向量结合使用?

MoreArgs

好吧,我们将不得不使用列表...

Error in mapply(rmultinom,MoreArgs = c(0.6,0.1)) : 
  argument 'MoreArgs' of 'mapply' is not a list

然后是我们向量的列表!

mapply(rmultinom,MoreArgs=list(0.6,0.1))
Error in (function (n,prob)  : unused arguments (0.3,0.1)

现在我们终于有了一些有用的东西。顺便说一下,> mapply(rmultinom,MoreArgs=list(c(0.6,0.1))) [[1]] [,] 4 8 9 [2,] 3 1 0 [3,] 3 1 1 [[2]] [,] 6 8 4 7 [2,] 4 3 7 3 [3,] 1 0 0 1 [[3]] [,] 7 6 9 8 7 [2,] 2 2 3 3 4 [3,] 3 4 0 1 1 也有效,但我认为这是因为 mapply(rmultinom,list(c(0.6,0.1))) 知道将 mapply 作为 list(c(0.6,0.1)) 传递。我很想知道是否有人可以证实这一点。可能的情况是 MoreArgs=list(c(0.6,0.1)) 正在回收 mapply 的第一个条目,这将是向量 list(c(0.6,0.1))将整个答案呈现为错误

假设以上不是回收的情况,那么我们可以自信地说,我们找不到一种矢量回收的方式来做我们想做的事情,因此回答了这个问题并表明我们需要{{1 }}。但作为奖励,值得展示如何使用匿名函数做到这一点:

c(0.6,0.1)

就个人而言,匿名函数的方式似乎更自然,但我认为如果参数太多,它可能会变得有点难看。 MoreArgsmapply(function(x,y,z) rmultinom(x,0.1)),10:12) [[1]] [,] 5 7 4 [2,] 4 2 5 [3,] 1 1 1 [[2]] [,] 5 7 5 5 [2,] 5 1 5 4 [3,] 1 3 1 2 [[3]] [,] 10 8 8 8 8 [2,] 2 2 3 3 3 [3,] 0 2 1 1 1 也有效,但我不知道它们是否安全或惯用。

,

我还没有看到通过简单地删除 MoreArgs= 参数并将相关部分传递给 ... 无法获得相同功能的情况。

这是错误的,但只是轻微的。比较:

options(max.print = 50)#Before running this,make sure that you know how to undo it.

> mapply(sum,1:5,MoreArgs=list(runif(10),runif(10000)))
[1] 5019.831 5020.831 5021.831 5022.831 5023.831

> mapply(sum,list(runif(10)),list(runif(10000)))
[1] 5069.321 5070.321 5071.321 5072.321 5073.321

> mapply(sum,list(runif(10),runif(10000)))
[1]    6.658275 4984.177882    8.658275 4986.177882   10.658275

> mapply(sum,runif(10),runif(10000))
 [1] 1.750417 3.286090 3.186474 5.310268 5.962829 1.343564 2.325567 3.928796 4.955376
[10] 5.507385 1.992290 3.454536 3.399763 5.242883 5.589296 1.637056 2.964259 3.839006
[19] 5.647123 5.883139 1.863512 2.827110 3.633137 5.174900 5.365155 2.022725 3.139846
[28] 3.830624 5.064546 5.697612 1.242803 3.456888 3.726114 5.271773 5.881724 1.533730
[37] 2.489976 3.509690 5.657166 5.400823 1.972689 2.858276 3.571505 5.582752 5.482381
[46] 1.956237 2.497409 3.864434 5.389969 5.965341
 [ reached getOption("max.print") -- omitted 9950 entries ]
Warning message:
In mapply(sum,runif(10000))) :
  longer argument not a multiple of length of shorter

在第一种情况下,MoreArgs 参数中列表的每个元素都会在每次调用时被回收。类似地,第二种情况是为每次调用回收 runif(10)runif(10000),给出我有信心称之为相同的行为。第 4 种情况仅用于展示如果我们愚蠢到根本不使用任何列表时我们会得到什么。

我上面引用的说法是第一种和第三种情况应该相同。情况显然不是这样。如果我们尝试在没有 MoreArgs 的情况下使用一个列表(而不是两个,就像我们的第二种情况那样),R 的正常向量回收规则将使我们对第一个、第三个和第五个重复使用 runif(10) 的值调用,并使用 runif(10000) 作为第二个和第四个,并由于这种奇怪的行为给我们一个警告。

总而言之,MoreArgs 参数似乎始终可以由 R 的向量回收规则替换(尽管我的 previous answer),但不是我在问题中所说的确切方式。事实似乎是 MoreArgs=list(foo,bar,etc) 等效于使用 list(foo)list(bar)list(etc) 作为 ...mapply 参数。请注意,这与使用 list(foo,etc) 作为 ... 参数不同。因此,最终:您不会总是通过省略 MoreArgs 参数获得相同的功能。

最后一个小细节:省略 MoreArgs 参数是无害的,但省略 ... 参数并使用 MoreArgs 代替 gives unexpected output,通常是一个空列表。>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。