如何在R中对此循环进行矢量化

时间:2013-02-21 19:44:28

标签: r loops for-loop vectorization

我在R中没有太多经验。我正在尝试编写一个Gibbs采样器,我有一个这样的for循环:

for (iNum in 1:totNum) {
    rateNum <- Y3[iNum]
    if(Y3[iNum] > 0) {
        yStar3[iNum] <- rtnorm(1, mean = Mean3[iNum], sd = sqrt(Var3), 
                 lower = gz[rateNum], upper = gz[rateNum + 1])
    } else if(Y3[iNum] == 0) {
    yStar3[iNum] <- rtnorm(1, mean = Mean3[iNum], sd = sqrt(Var3), 
                  lower = -Inf, upper = Inf);
    }
}

这花费了太多时间。我尝试使用lapply,但这还不够快。有没有办法对这个循环进行矢量化?

谢谢你,最好的问候!!

3 个答案:

答案 0 :(得分:2)

所以,似乎你没有迭代之间的依赖关系,这使得它非常简单地进行矢量化

  lhs = rtnorm(length(Y3), mean = Mean3, sd = sqrt(Var3), lower = gz[Y3],
              upper = gz[Y3 + 1])
  rhs = rtnorm(length(Y3), mean=Mean3, sd = sqrt(Var3), lower=-Inf, upper=Inf)

  ifelse(Y3 > 0, lhs, rhs) 

这里的问题是rtnorm必须在其输入参数(mean,lower和upper)上进行矢量化。可能不是这种情况,在这种情况下,你将不得不做更多的工作。

答案 1 :(得分:2)

最简单的方法是生成条件的两半并选择您想要的那一半。 mean参数将采用向量方式,因此您可以得到如下内容:

yStar3 <- ifelse(
  Y3 > 0,
    rtnorm(totNum, mean=Mean3, sd=sqrt(Var3), lower=gz[ratenum], upper=gz[rateNum+1]),
    rtnorm(totNum, mean=Mean3, sd=sqrt(Var3), lower=-Inf, upper=Inf))

您必须优化ifelse,可能还有一个附加条件,即Y3小于零的情况,但这是一般的想法。

更新:@hadley建议在rtnorm中移动ifelse:

yStar3 <- rtnorm(totNum, mean=Mean3, sd=sqrt(Var3),
  lower=ifelse(Y3>0,gz[rateNum], -Inf),
  upper=ifelse(Y3>0,gz[rateNum+1], Inf))

现在基本上没有不必要的计算。

更新:当然,正如评论者指出的那样,1是错误的;它应该是totNum。

答案 2 :(得分:1)

如果您的变量没有一些值,这是一个问题,但您想要做的事情是相当简单的。你想坚持使用所有的矢量化语句,尽量不要占用太多内存。这是基本策略:

第1步:弄清楚如何计算所有数字。

# The number of values you need from 'rtnorm'
sum(Y3 > 0)
sum(Y3 == 0)

# The means you need from the 'Mean3' array
Mean3[Y3 > 0]
Mean3[Y3 == 0]

# Lower and upper limits for Y3 > 0
gz[Y3[Y3 > 0]]
gz[Y3[Y3 > 0] + 1]

第2步:在yStar3的矢量过滤器上使用这些值。如果没有一些示例数据和变量值,我不能完全确定我的所有语法都是完美的,但它看起来应该是这样的:

yStar3[Y3 > 0] <- rtnorm(
  sum(Y3 > 0), 
  mean = Mean3[Y3 > 0], 
  sd = sqrt(Var3), 
  lower = gz[Y3[Y3 > 0]], 
  upper = gz[Y3[Y3 > 0] + 1])

yStar3[Y3 == 0] <- rtnorm(
  sum(Y3 == 0), 
  mean = Mean3[Y3 == 0], 
  sd = sqrt(Var3), 
  lower = -Inf, 
  upper = Inf)