【问题标题】:How to write for loop when function increases with each iteration?当每次迭代函数增加时如何编写for循环?
【发布时间】:2013-11-21 23:24:31
【问题描述】:

我试图估计当动物被移除并且检测在时间和空间上发生变化时,在多个观察期内从 n.sites 检测到动物的概率。如果我在 5 个观察期内做这样的事情,它会起作用:

for(i in 1:nsites){
  mu[i,1] <- p[i,1]
  mu[i,2] <- p[i,2]*(1-p[i,1])
  mu[i,3] <- p[i,3]*(1-p[i,1])*(1-p[i,2])
  mu[i,4] <- p[i,4]*(1-p[i,1])*(1-p[i,2])*(1-p[i,3])
  mu[i,5] <- p[i,5]*(1-p[i,1])*(1-p[i,2])*(1-p[i,3])*(1-p[i,4])
}

时间 2 的概率取决于时间 1 的概率,时间 3 的概率取决于时间 1 和时间 2 的概率。如果我只在 5 个时间段内执行此操作,它不会很大把这个写出来。但是当我得到 10、15、20 多个时间段时,写出来是相当混乱的。我觉得应该有一种方法可以编写此循环而无需输入每个步骤,但我就是想不出该怎么做。也许附加索引或其他控制语句或电源功能。如果 p[i] 在每个 jth 观察中都相同(即 p[i,1] = p[i,2] = p[i,3] 等),它将是:

p[i]*(1-p[i])^5

任何建议将不胜感激。

这是 BUGS 语言代码。我在 R 中工作并通过 rjags 包将代码发送到 JAGS。 BUGS、R 或伪代码都适合我的目的。

这是模拟问题的 R 代码:

set.seed(123)
testp <- matrix(runif(108, 0.1, 0.5), 108, 5)
testmu <- matrix(NA, 108, 5)

for(i in 1:nsites){
  testmu[i,1] <- testp[i,1]
  testmu[i,2] <- testp[i,2]*(1-testp[i,1])
  testmu[i,3] <- testp[i,3]*(1-testp[i,1])*(1-testp[i,2])
  testmu[i,4] <- testp[i,4]*(1-testp[i,1])*(1-testp[i,2])*(1-testp[i,3])
  testmu[i,5] <- testp[i,5]*(1-testp[i,1])*(1-testp[i,2])*(1-testp[i,3])*(1-testp[i,4])
}

感谢您的帮助。 丹

【问题讨论】:

    标签: r for-loop winbugs jags


    【解决方案1】:

    这看起来确实很适合 R 的Reduce

    testmu3 <- matrix(NA, 108, 5)
    nsites = 108
    np = 5
    
    for (i in 1:nsites) {
       testmu3[ i, ] <- Reduce( function(x,y) x*(1-y), testp[i, ], 
                                                       accumulate=TRUE)
    }
    max(abs(testmu3-testmu))
    [1] 0
    

    accumulate 参数创建一个不断增长的中间结果向量。

    > testp[1, ]
    [1] 0.215031 0.215031 0.215031 0.215031 0.215031
    
    > Reduce( function(x,y) x*(1-y), testp[1, ],  accumulate=TRUE)
    [1] 0.21503101 0.16879267 0.13249701 0.10400605 0.08164152
    

    【讨论】:

    • +1,酷。我不知道accumulate 选项,尽管我经常使用Reduce。对于 OP 的参考...也可以在这里消除循环,使用 t(apply(testp,1,function(z) Reduce( function(x,y) x*(1-y),z,accumulate=TRUE)))
    • 实际上我以前从未听说过 Reduce 函数。很整齐。感谢您的回答以及新功能!
    【解决方案2】:

    @Frank 的答案更简洁(可能更快),但这也可行,并且可能更容易理解。

    testmu2 <- matrix(NA, 108, 5)
    nsites = 108
    np = 5
    
    for (i in 1:nsites) {
      fac <- 1
      testmu2[i,1] <- testp[i,1]
      for (j in 2:np) {
        fac <- fac * (1-testp[i,j-1])
        testmu2[i,j] <- testp[i,j] * fac
      }
    }
    max(abs(testmu2-testmu))
    [1] 2.775558e-17
    

    【讨论】:

    • +1。我不知道它是否更容易阅读,但我可能会将内部循环的主体写为testmu2[i,j] &lt;- testp[i,j]*(fac &lt;- fac * (1-testp[i,j-1]))
    • @Frank - 我什至不知道你可以在一行上使用两个作业。谢谢#somuchtolearn
    • 您对速度的估计是正确的。弗兰克的方法比你我的快十倍。
    • 我选择这个是因为它更通用(不使用 R 特定的函数)。它可能在 BUGS 语言中仍然存在问题,因为正在重新分配 fac,但我希望可以解决这个问题。
    【解决方案3】:

    这是一种方法:

    testmu2 <- testp*t(apply(cbind(1,1-testp[,-5]),1,cumprod))
    

    在我的电脑上,它们几乎匹配:

    > max(abs(testmu2-testmu))
    [1] 2.775558e-17
    

    我不知道 BUGS/JAGS,但我们的想法是先将 1-p 矩阵的累积乘积跨列计算,然后再计算 p*result。

    【讨论】:

    • 非常漂亮,谢谢。我仍然难以理解 apply 函数。 for 循环对我来说更自然,但 apply 函数要快得多。
    猜你喜欢
    • 2017-02-09
    • 2023-03-11
    • 1970-01-01
    • 2022-01-17
    • 2013-09-25
    • 1970-01-01
    • 2012-05-19
    • 2018-02-13
    • 2021-12-27
    相关资源
    最近更新 更多