2016-11-04 7 views
-1

私はシミュレーションの研究をしており、次のRコードを書いています。ループを2つ使用せずにこのコードを書いたり、より効率的にする(より速く実行する)方法はありますか?このRコード(forループ)をより効率的にするには?

S = 10000 
n = 100 
v = c(5,10,50,100) 
beta0.mle = matrix(NA,S,length(v)) #creating 4 S by n NA matrix 
beta1.mle = matrix(NA,S,length(v)) 
beta0.lse = matrix(NA,S,length(v)) 
beta1.lse = matrix(NA,S,length(v)) 
for (j in 1:length(v)){ 
    for (i in 1:S){ 
    set.seed(i) 
    beta0 = 50 
    beta1 = 10 
    x = rnorm(n) 
    e.t = rt(n,v[j]) 
    y.t = e.t + beta0 + beta1*x 
    func1 = function(betas){ 
     beta0 = betas[1] 
     beta1 = betas[2] 
     sum = sum(log(1+1/v[j]*(y.t-beta0-beta1*x)^2)) 
     return((v[j]+1)/2*sum) 
    } 
    beta0.mle[i,j] = nlm(func1,c(1,1),iterlim = 1000)$estimate[1] 
    beta1.mle[i,j] = nlm(func1,c(1,1),iterlim = 1000)$estimate[2] 
    beta0.lse[i,j] = lm(y.t~x)$coef[1] 
    beta1.lse[i,j] = lm(y.t~x)$coef[2] 
    } 
} 

nlm機能のために使用される第二forループ内機能func1(エラーをt分布している場合MLE見つけるために)。 Rでparallelパッケージを使いたかったのですが、便利な機能が見つかりませんでした。

+0

達成しようとしていることの説明を教えてもらえますか?すなわち、ループ**が何をしているべきか、出力が何を期待しているのでしょうか? – SymbolixAU

+0

ループ内でfunc1を定義する理由は、パラメータとしてj、xを渡すのではなく、なぜなら – dww

+0

'lineprof'が最も遅いステップを見つけるのに役立つかもしれません。 – mt1022

答えて

2

Rで高速実行するための鍵は、forループをベクトル化された関数(applyファミリなど)に置き換えることです。さらに、プログラミング言語に関しては、同じパラメータで高価な関数(例えば、nlmなど)を複数回呼び出す場所を探し、毎回再計算するのではなく、結果を格納できる場所を確認する必要があります。

ここでは、パラメータを定義したように開始します。 beta0beta1の場合は常に5010なので、ここでもそれらを定義します。

S <- 10000 
n <- 100 
v <- c(5,10,50,100) 
beta0 <- 50 
beta1 <- 10 

次に、ループの外側にfunc1を定義して、毎回再定義しないようにします。 func1には、新しい値で呼び出すことができるように、2つの追加パラメータ、vy.tが追加されました。

func1 <- function(betas, v, y.t, x){ 
    beta0 <- betas[1] 
    beta1 <- betas[2] 
    sum <- sum(log(1+1/v*(y.t-beta0-beta1*x)^2)) 
    return((v+1)/2*sum) 
} 

実際に実際の作業を行います。ネストされたループを持つのではなく、ネストした適用ステートメントを使用します。外側lapplyあなたがSの各値に対して(beta0.mlebeta1.mlebeta0.slebeta1.lse)取得したい4つの値のために行列を作りますvと内側vapplyの各値のリストを作成します。

最後に、すべてを4つのマトリックスに再編成することができます。

beta0.mle <- vapply(values, function(x) x["beta0.mle", ], numeric(S)) 
beta1.mle <- vapply(values, function(x) x["beta1.mle", ], numeric(S)) 
beta0.lse <- vapply(values, function(x) x["beta0.lse.(Intercept)", ], numeric(S)) 
beta1.lse <- vapply(values, function(x) x["beta1.lse.x", ], numeric(S)) 

最後の注意として、あなたがシードを設定するSインデックスを使用している理由に応じて、さらに高速に実行するために、これを再編成することも可能です。 xを生成するために使用されたシードがrnormであることが重要である場合は、これが最善の方法です。しかし、vのすべての値が同じ値のxでテストされていることを確認するためにのみ行う場合は、replicateを使用して速度を上げる可能性があります。

+0

'apply'はループ非依存であり、ベクトル化ではありません。 'for'から' apply'に移行することで小さなスピードアップが可能ですが、本当のベクトル化のために 'for'または' apply'から移動するスピードアップと混同すべきではありません。より大きい。例えば、[Rは家族の統語的砂糖を適用していますか?](http://stackoverflow.com/a/2276001/903061)または[R Infernoのサークル4](http://www.burns-stat.com/ pages/Tutor/R_inferno.pdf)。 – Gregor

+0

あなたは 'for'ループの隠蔽とベクトル化についてのポイントを持っていますが、これは定義ベクトル化があいまいになっていると感じています。ベクタライズされた関数を呼び出して、入力のベクトルを受け取り、そのベクトルに最適化されている関数を呼び出すと、それは修飾されます。そのベクトル全体を同時に評価するものと呼んでも、それはありません。あなたが引用した投稿は、 '〜'から ''適用 ''に切り替えるための3〜10倍のスピードアップを示す答えでいっぱいです。 'apply'との大きな違いは、ループと変数の作成が' R'ではなく 'C'で起こることです。これはずっと高速です。 – Barker

+0

これは本当ですが、時には適用に切り替える際に見られる劇的なスピードアップは、ループ内で何が起こっているのが些細なのかにありがちです(Johnの答えを参照)。実際のケースでは、この場合のように、ループ本体は何か自明ではありません。あなたはコードを再構成したやり方で、この回答に非常に良い効率改善をしました。私はあなたが、改善の大半が 'vapply'を使うことによる印象を与えていると思いますが、それは本当にケーキのアイシングです。 – Gregor

関連する問題