使用代码优化加速R中的模拟

时间:2017-09-26 16:44:34

标签: r optimization simulation

我正在尝试做的通用版本是进行模拟研究,我操纵一些变量来看看它是如何影响结果的。我对R有一些速度问题。最新的模拟工作了几次迭代(每次实验10次)。但是,当我转向大规模(每个实验10k)版本时,模拟已经运行了14个小时(并且仍然在运行)。

以下是我正在运行的代码(带注释)。作为R的新秀,我正努力优化模拟效率。我希望从这里提供的意见和建议中学习优化这些代码,并将这些意见用于未来的模拟研究。

让我说一下这段代码应该做什么。我正在操纵两个变量:效果大小和样本大小。每种组合运行10k次(即每个条件10k个实验)。我初始化一个数据框来存储我的结果(称为结果)。我循环了三个变量:效果大小,样本大小和迭代(10k)。

在循环中,我初始化了四个NULL组件:p.test,p.rep,d.test和d.rep。前两个捕获初始t检验的p值和复制的p值(在类似条件下复制)。后两者计算效果大小(科恩的d)。

我从控制条件的标准法线(DVcontrol)生成随机数据,并使用我的效果大小作为实验条件(DVexperiment)的平均值。我取值之间的差异,并将结果抛入R中的t检验函数(配对样本t检验)。我将结果存储在一个名为Trials的列表中,然后将其绑定到Results数据框。该过程重复10k次直至完成。

# Set Simulation Parameters
## Effect Sizes (ES is equal to mean difference when SD equals Variance equals 1)
effect_size_range <- seq(0, 2, .1) ## ES
## Sample Sizes
sample_size_range <- seq(10, 1000, 10) ## SS
## Iterations for each ES-SS Combination
iter <- 10000

# Initialize the Vector of Results
Results <- data.frame()

# Set Random Seed
set.seed(12)

# Loop over the Different ESs
for(ES in effect_size_range) {

  # Loop over the Different Sample Sizes
  for(SS in sample_size_range) {

    # Create p-value Vectors
    p.test <- NULL
    p.rep <- NULL
    d.test <- NULL
    d.rep <- NULL

    # Loop over the iterations
    for(i in 1:iter) {

      # Generate Test Data
      DVcontrol <- rnorm(SS, mean=0, sd=1)
      DVexperiment <- rnorm(SS, mean=ES, sd=1)
      DVdiff <- DVexperiment - DVcontrol
      p.test[i] <- t.test(DVdiff, alternative="greater")$p.value
      d.test[i] <- mean(DVdiff) / sd(DVdiff)

      # Generate Replication Data
      DVcontrol <- rnorm(iter, mean=0, sd=1)
      DVexperiment <- rnorm(iter, mean=ES, sd=1)
      DVdiff <- DVexperiment - DVcontrol
      p.rep[i] <- t.test(DVdiff, alternative="greater")$p.value
      d.rep[i] <- mean(DVdiff) / sd(DVdiff)
    }

    # Results
    Trial <- list(ES=ES, SS=SS,
                  d.test=mean(d.test), d.rep=mean(d.rep),
                  p.test=mean(p.test), p.rep=mean(p.rep),
                  r=cor(p.test, p.rep, method="kendall"),
                  r.log=cor(log2(p.test)*(-1), log2(p.rep)*(-1), method= "kendall"))
    Results <- rbind(Results, Trial)
  }
}

提前感谢您的意见和建议, 约什

1 个答案:

答案 0 :(得分:2)

优化的一般方法是运行profiler来确定解释器花费最多时间的代码部分,然后优化该部分。我们假设您的代码位于名为test.R的文件中。在R中,您可以通过运行以下命令序列对其进行分析:

Rprof()              ## Start the profiler
source( "test.R" )   ## Run the code
Rprof( NULL )        ## Stop the profiler
summaryRprof()       ## Display the results

(请注意,这些命令将在R会话的目录中生成文件Rprof.out。)

如果我们在您的代码上运行探查器(使用iter <- 10而不是iter <- 10000),我们会获得以下个人资料:

# $by.self
#                         self.time self.pct total.time total.pct
# "rnorm"                      1.56    24.53       1.56     24.53
# "t.test.default"             0.66    10.38       2.74     43.08
# "stopifnot"                  0.32     5.03       0.86     13.52
# "rbind"                      0.32     5.03       0.52      8.18
# "pmatch"                     0.30     4.72       0.34      5.35
# "mean"                       0.26     4.09       0.42      6.60
# "var"                        0.24     3.77       1.38     21.70

从这里开始,我们发现rnormt.test是您最昂贵的操作(不应该让您感到惊讶,因为这些操作位于您最内层的循环中)。

一旦你弄清楚昂贵的函数调用的位置,实际的优化包括两个步骤:

  1. 优化功能,和/或
  2. 优化调用函数的次数。
  3. 由于t.testrnorm是内置R函数,上面步骤1的唯一选择是寻找可能从正态分布和/或运行中更快地实现采样的替代包多次测试。第2步实际上是以不会多次重新计算同一事物的方式重构代码。例如,以下代码行不依赖于i

    # Generate Test Data
    DVcontrol <- rnorm(SS, mean=0, sd=1)
    DVexperiment <- rnorm(SS, mean=ES, sd=1)
    

    将这些移到循环之外是否有意义,或者您是否真的需要为i的每个不同值提供测试数据的新样本?