2017-09-26 6 views
0

私がやっていることの一般的なバージョンは、いくつかの変数を操作して結果にどのような影響があるかを見るシミュレーション研究を行うことです。私はRでいくつかのスピードの問題を抱えています。最新のシミュレーションは、いくつかの反復(実験ごとに10回)で動作しました。しかし、私が大規模(実験あたり10k)バージョンに移行したとき、シミュレーションは14時間実行されています(まだ実行中です)。コード最適化を使用したRでのシミュレーションの高速化

以下は、私が実行しているコードです(コメントあり)。 Rとのルーキーであり、効率的にシミュレーションを最適化しようとしています。このコードを最適化し、これらのコメントを将来のシミュレーション研究に使用するために、ここで提供されたコメントと提案から学ぶことが、私の希望です。

このコードの動作について、いくつかご説明します。私は2つの変数を操作しています:エフェクトサイズとサンプルサイズ。各組み合わせは10k回実行されます(条件ごとに10k回の実験)。データフレームを初期化して結果(結果)を保存します。エフェクトサイズ、サンプルサイズ、および繰り返し(10k)の3つの変数にループします。

ループ内では、p.test、p.rep、d.test、およびd.repの4つのNULLコンポーネントを初期化します。前者の2つは、最初のt検定のp値と複製のp値(同様の条件で複製)を取得します。後者の2つはエフェクトのサイズを計算します(コーエンのd)。

コントロール条件(DVcontrol)の標準標準からランダムデータを生成し、実験条件(DVexperiment)の平均値として自分のエフェクトサイズを使用します。私は値の差を取って、その結果をRのt検定関数に投げます(paired-samples t-test)。私はTrialsと呼ばれるリストに結果を格納し、結果データフレームにこれをバインドします。このプロセスは完了まで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) 
    } 
} 

おかげで、 ジョシュ

+2

これは、ここではなく[codereview.se]に属しているようです。 –

+2

@JohnColeman私は両方のサイトで話題になっていると思います。具体的な質問です(「このコードの速度を上げるにはどうすればいいですか?それは1日かかる」)とコードレビューのリクエストです。 – Zeta

+0

この投稿を削除し、必要に応じてコードレビューに移動することができます。 – Josh

答えて

2

最適化への一般的なアプローチは、インタプリタがで最も時間を費やしているコードのどの部分を決定するためにprofilerを実行し、その後にすることですその部分を最適化する。コードがtest.Rというファイルにあるとします。私たちは、プロファイラを実行する場合

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

(これらのコマンドは、あなたのRセッションのディレクトリ内のファイルRprof.outを生成することに注意してください。)

:Rでは、あなたは、次の一連のコマンドを実行することによってそれをプロファイルすることができます(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があなたの最も高価な操作(あることを確認しますこれらがあなたの最も内側のループにあるので、実際には驚きではありません)。

高価な関数呼び出しがどこにあるかあなたが考え出したら、実際の最適化は、2つのステップで構成されています

  1. 関数が呼び出された回数を最適化機能の最適化、および/または
  2. t.testrnorm以来

がビルトインされているRの機能、上記のステップ1のためのあなたの唯一のオプションは、正規分布からのサンプリングの高速化の実装を持っている、および/または複数のt検定を実行していることがあり、代替のパッケージを探すことです。ステップ2は、同じことを何度も再計算しない方法でコードを再構築することです。たとえば、次のコード行はiに依存しません。

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

それはループの外でこれらを移動しても意味がない、またはあなたが本当にiのそれぞれ異なる値についてテストデータの新しいサンプルが必要なのか?

+0

あなたのコメントありがとう!あなたの質問に答えるために、実験の条件を複数回(この場合は10k)繰り返す必要があるため、私はループの外にそのビットを移動することはできません。さもなければ、それはすばらしい解決策になるでしょう。 – Josh

+1

Gotcha。いずれにしても、ループの外側に 'rnorm'呼び出しを移動することもできますが、一度に' SS * iter'値をサンプリングするようにすることもできます(つまり、1回の呼び出しですべてのループ反復のすべての値)。ループ内のサンプルの適切な部分にコードをアクセスさせることができます。 'rnorm'呼び出しに伴うオーバヘッドが多い場合は、コードを高速化する必要があります。 –

+2

別の考え方: 'DVcontrol'と' DVexperiment'を直接使用することはなく、その違いだけです。しかし、2つの正規分布の違いも正常です:http://mathworld.wolfram.com/NormalDifferenceDistribution.html。なぜ、 'DVdiff'値を直接生成しないで、' rnorm'呼び出しの数を50%減らすのでしょうか? –

関連する問題