【问题标题】:R apply with dynamic argumentR 应用动态参数
【发布时间】:2017-01-06 16:06:28
【问题描述】:

我只是想知道是否可以使用 apply 函数,以便在使用下一个 i 索引之前,刷新其中一个参数。让我介绍一个例子:

我有一个简单的 10 元素向量:

a<-c(1,rep(NA,9))

并定义一个函数,将 a 的第 i 个元素替换为 2 和前一个元素的总和:

fun<-function(i,vec){
  vec[i]<-2+cumsum(vec)[i-1]
  a<<-vec
}

现在我想使用 sapply,f.e.

sapply(2:10,fun,vec=a)

所以结果我得到向量1,3,...19

我知道在 for 循环中很容易完成,但我会尝试申请看看它是否是更快的解决方案。

感谢您的任何建议!

巴特

【问题讨论】:

  • 最好的解决方案总是矢量化:1 + (0:9) * 2
  • 有副作用的函数很危险&lt;&lt;-
  • 当然矢量化是最好的,但真正的问题更复杂。我在以下步骤中添加的内容取决于之前的结果(之前填充的 a 值)——这里的示例很简单,只是为了展示这个想法
  • 你不清楚你的向量a的构成。例如。它的哪些属性是可变的(第一个值,任何值,长度)。对于您的示例,@Roland 显示了解决方案。
  • 请提供一个具体且有代表性的例子。 *apply 循环仍然是循环,并不比编写良好的 for 循环快(vapply 稍有例外)。但是,如果您的问题是真正的递归问题,那么使用编译语言(即 Rcpp)通常是最简单和最好的。

标签: r loops dynamic arguments apply


【解决方案1】:

据我所知,您无法使用 *apply 系列进行此类计算。

编辑:操作,刚刚看到答案。让我换个说法,如果没有全局分配 ' 就无法完成

原因是 *apply 需要预先输入所有值。任何像你这样的递归函数,如果没有转换,你就无法工作。

我看到了一种添加 *apply 函数并使其更快的方法,但它需要您进行一些数学运算:您可以尝试求解方程的递归。

使用给出的示例,我们得到了。

vec[i] = 2 + cumsum(vec[i-1])

数学上相当于:

vec[i]= 2 +2 +cumsum(vec[i-2])+cumsum(vec[i-2])

根据这个推理,我们得到:

vec[i]=2*i +vec[1]*i

可以在 lapply 中使用:

non.rec <- function(x,initial) {2*x+initial*x}
lapply(2:10,non.rec,initial=1)

这可能非常复杂,具体取决于您正在处理的功能。因此,您需要在简化此方程式所花费的时间和计算机获得的速度之间进行权衡。

【讨论】:

  • 感谢您的评论!不幸的是,我正在处理没有分析解决方案的 SDE,但我同意当应用于简单问题时,您的解决方案非常简洁。
【解决方案2】:

如果我理解正确,以下代码是您问题的可能解决方案。正如@jogo 在您的问题的 cmets 中提到的那样,深度分配函数 &lt;&lt;- 会导致可能很危险的副作用。为了让您的代码正常工作,我应用了 a 的索引而不是元素。

循环在 R 中的评价很差,但它们并不总是坏事。在这种情况下,我想出的适合您的解决方案的 sapply 实际上比竞争的循环解决方案(使用 microbenchmark 测量)要慢,并且循环具有不依赖副作用的优点。

应用解决方案

a <- c(1,rep(NA,9))
fun<-function(i,vec){
  a[i] <<- 2+cumsum(vec)[i-1]
}

sapply(seq_along(a)[-1], function(i) fun(i,a))

循环与 sapply

loopSoln  <- function() {
  a <- c(1,rep(NA,9))
  for(i in seq_along(a)[-1]) {
    a[i] <- 2+cumsum(a)[i-1]
  }
  return(a)
}


fun<-function(i,vec){
    a[i] <<- 2+cumsum(vec)[i-1]
  }
applySoln <- function() {
  a <- c(1,rep(NA,9))
  sapply(seq_along(a)[-1], function(i) fun(i,a))
  return(a)
}

microbenchmark::microbenchmark(loopSoln(), applySoln())

Unit: microseconds
       expr    min      lq     mean  median      uq     max neval
 loopSoln() 28.915 30.6960 34.36206 32.5115 33.9085  99.525   100
applySoln() 77.664 80.9815 88.13986 83.1465 85.3815 207.569   100

【讨论】:

  • 非常感谢!如果真的可以节省一些计算时间,我一定会尝试您的解决方案并返回信息。
猜你喜欢
  • 2016-09-15
  • 2015-07-29
  • 1970-01-01
  • 1970-01-01
  • 2019-01-12
  • 2011-11-03
  • 2017-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多