嵌套for循环的效率

时间:2012-10-22 22:32:25

标签: r

我已经创建了以下代码,它在R中的for循环中嵌套for循环。它是一个计算Power的模拟。我已经知道R对于做循环并不是很好,但我想知道是否有任何效率可以让我的运行速度更快一些。我对R以及任何类型的编程都很新。现在我看到的运行时间是:

m = 10我得到.17秒

m = 100我得到3.95秒

m = 1000我得到246.26秒

m = 2000我得到1003.55秒

我希望设定采样的次数,m,超过100K,但我甚至不敢将其设置为10K

以下是代码:

m = 1000                        # number of times we are going to  take samples
popmean=120                     # set population mean at 120
popvar=225                      # set known/established population 
variance at 225
newvar=144                      # variance of new methodology 
alpha=.01                       # set alpha
teststatvect = matrix(nrow=m,ncol=1)    # empty vector to populate with test statistics
power = matrix(nrow=200,ncol=1)     # empty vector to populate with power

system.time(                    # not needed - using to gauge how long this takes
    for (n in 1:length(power))          # begin for loop for different sample sizes
      for(i in 1:m){                # begin for loop to take "m" samples
      y=rnorm(n,popmean,sqrt(newvar))   # sample of size n with mean 120 and var=144
      ts=sum((y-popmean)^2/popvar)      # calculate test statistic for each sample
      teststatvect[i]=ts            # loop and populate the vector to hold test statistics
      vecpvals=pchisq(teststatvect,n)   # calculate the pval of each statistic
      power[n]=length(which(vecpvals<=alpha))/length(vecpvals) # loop to populate      power vector. Power is the proportion lessthan ot equal to alpha
        }
   }
 )

2 个答案:

答案 0 :(得分:3)

我重新组织了你的代码并摆脱了内循环。

  • 对一个随机数的长矢量进行采样(然后将其折叠成矩阵)比重复采样短矢量(replicate快得多,如另一个答案中所建议的那样,对于可读性很好,但在这种情况下你通过对块中的随机数进行采样可以做得更好)
  • colSums比在for循环内汇总或使用apply更快。
  • 它只是糖(即实际上效率不高),但您可以使用mean(pvals<=alpha)代替sum(pvals<=alpha)/length(alpha)
  • 我定义了一个函数来返回指定参数集(包括样本大小)的幂,然后使用sapply来调整大小向量的范围(不比for循环快,但是更清洁,也许更容易概括)。

代码:

powfun <- function(ssize=100,
                   m=1000,      ## samples per trial
                   popmean=120, ## pop mean
                   popvar=225,  ## known/established pop variance
                   newvar=144,  ## variance of new methodology
                   alpha=0.01,
                   sampchisq=FALSE)  ## sample directly from chi-squared distrib?
{
    if (!sampchisq) {
      ymat <- matrix(rnorm(ssize*m,popmean,sd=sqrt(newvar)),ncol=m)
      ts <- colSums((ymat-popmean)^2/popvar)          ## test statistic
    } else {
      ts <- rchisq(m,df=ssize)*newvar/popvar
    }
    pvals <- pchisq(ts,df=ssize)                    ## pval
    mean(pvals<=alpha)                              ## power
}

你真的需要样本大小的每个整数值的功率,或者更宽的间距样本是否正常(如果你需要精确值,插值可能非常准确)

ssizevec <- seq(10,250,by=5)
set.seed(101)
system.time(powvec <- sapply(ssizevec,powfun,m=5000))  ## 13 secs elapsed

速度相当快,如果需要,可能会让你达到m=1e5,但我不太清楚为什么你需要那些精确的结果 - 功率曲线相当平滑{{1} } ...

如果您不耐烦地等待长时间的模拟,您还可以通过将m=5000替换为sapply(ssizevec,powfun,m=5000)来获取打印进度条

最后,我认为你可以通过直接采样卡方值或通过分析功率计算(!)来加快整体速度。我认为library(plyr); aaply(ssizevec,.margins=1,powfun,.progress="text",m=5000)相当于循环的前两行,你甚至可以直接对卡方密度进行数值计算......

rchisq(m,df=ssize)*newvar/popvar

(我刚试过这个,在样本大小的每个值上从1到200抽样system.time(powvec2 <- sapply(ssizevec,powfun,m=5000,sampchisq=TRUE)) ## 0.24 seconds elapsed ......需要24秒......但我仍然认为这可能是不必要的。)

图片:

m=1e5

enter image description here

答案 1 :(得分:0)

一般而言,您希望尽可能利用矢量化,而不是速度与可读性/理解力。

为什么在内部循环中写入power[n](我想也计算vecpals)?内循环执行后,不应该在外循环中吗?您可能希望在两个循环外部移动平方根的计算。

为什么teststatvectpower被初始化为矩阵(明确是二维数组)而不是向量(或者更确切地说,作为一维数组,使用array)? variance at 225只是上一行评论的结尾吗?您可能想要检查格式。 (这是家庭作业吗?)

对于你在这里尝试做的事情,你可能想要利用非常方便的函数replicate,也许通过编写一个特定的函数来调用它。