我正在尝试做的通用版本是进行模拟研究,我操纵一些变量来看看它是如何影响结果的。我对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)
}
}
提前感谢您的意见和建议, 约什
答案 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
从这里开始,我们发现rnorm
和t.test
是您最昂贵的操作(不应该让您感到惊讶,因为这些操作位于您最内层的循环中)。
一旦你弄清楚昂贵的函数调用的位置,实际的优化包括两个步骤:
由于t.test
和rnorm
是内置R函数,上面步骤1的唯一选择是寻找可能从正态分布和/或运行中更快地实现采样的替代包多次测试。第2步实际上是以不会多次重新计算同一事物的方式重构代码。例如,以下代码行不依赖于i
:
# Generate Test Data
DVcontrol <- rnorm(SS, mean=0, sd=1)
DVexperiment <- rnorm(SS, mean=ES, sd=1)
将这些移到循环之外是否有意义,或者您是否真的需要为i
的每个不同值提供测试数据的新样本?