0

打ち切り率を0または1にできないシミュレーションデータを生成する必要があります。そのため、whileループを使用します。問題は、カウントを(5ではなく)10,000に増やすと、プログラムが非常に遅くなることです。400の異なるシナリオでこれを繰り返さなければならないので、非常に遅くなります。コードを1つずつベクトル化できる場所を見つけようとしています。whileループを回避し、状態を維持するにはどうすればよいですか?

もう1つのアプローチは、whileループを維持し、基準を満たす10,000個のデータセットのリストを生成してから、その関数をリストに適用することです。ここでは例としてsummary関数を使用していますが、実際の関数はX_afterとdeltaの両方を使用しています(つまり、mle(X_after、delta))。whileループを使用する必要がある場合、これはより良いオプションですか?

私が抱えているもう1つの懸念は、メモリの問題です。このような大規模なシミュレーションを実行しているときにメモリを使い果たすのを防ぐにはどうすればよいですか?

mu=1 ; sigma=3 ; n=10 ; p=0.10
dset <- function (mu,sigma, n, p) {              
   Mean <- array()
   Median <- array()
   Pct_cens_array <- array()
   count = 0
   while(count < 5) { 

     lod <- quantile(rlnorm(100000, log(mu), log(sigma)), p = p)
     X_before <- rlnorm(n, log(mu), log(sigma))
     X_after <-  ifelse(X_before <= lod, lod,  X_before)
     delta <- ifelse(X_before <= lod, 1,  0) 
     pct_cens <- sum(delta)/length(delta)
     # print(pct_cens)
     if (pct_cens == 0 | pct_cens == 1 ) next
     else {
        count <-  count +1
        if (pct_cens > 0 & pct_cens < 1) {
             sumStats <- summary(X_after)
             Median[count] <- sumStats[3]
             Mean [count]<- sumStats[4]
             Pct_cens_array [count] <- pct_cens 
             print(list(pct_cens=pct_cens,X_after=X_after, delta=delta, Median=Median,Mean=Mean,Pct_cens_array=Pct_cens_array))
          }
       }
    }

          return(data.frame(Pct_cens_array=Pct_cens_array, Mean=Mean, Median=Median)) 
 }
4

2 に答える 2

2

私が C プログラミングで学んだ最初のルール: 分割して統治する! つまり、最初に複数の関数を作成し、それらをループに呼び出す必要があります。これは、このループがあまりにも多くの異なることを行うためです。そして、私はあなたのアルゴリズムについて心配しています:

if (pct_cens == 0 | pct_cens == 1 ) next
            else {count <-  count +1

for の代わりに while を使用する理由はありますか? ループ while と for には違いがあります。while では、for ではなく常に最初のループがあります。

最後に、問題について: 配列でより多くのメモリを使用して速度を上げます。例:

lod <- quantile(rlnorm(100000, log(mu), log(sigma)), p = p)
            X_before <- rlnorm(n, log(mu), log(sigma))

log(mu) と log(sigma) は 2 回計算されます。変数を使用して結果を保存すると、時間は節約されますが、もちろんより多くのメモリを消費します。

于 2012-04-10T06:34:07.590 に答える
2

コード全体のスタイルを変更することなく、コードにいくつかの微調整を加えました。Yoong Kim のアドバイスに耳を傾け、コードをより小さな断片に分割して、より読みやすく保守しやすくすることをお勧めします。

  • 関数は、各行にあるサンプルの数と、必要な反復 (列) の数に対して、2 つの "n" 引数を取得します。

  • 配列を拡大していてMedianMeanループ内で、メモリの再割り当てとコピーに多くの手間がかかり、すべてが遅くなります。X_afterこれを回避するために、ループの後に平均と中央値の計算を事前定義して移動しました。(おまけとして、mean呼び出さmedianれるのは 1 回だけn_iterationです。)

  • への呼び出しifelseは実際には必要ありませんでした。

  • rlnorm2 回呼び出すよりも、1 回呼び出して x と lod に十分な値を生成する方が少し速くなります。

更新された関数は次のとおりです。

dset2 <- function (mu, sigma, n_samples, n_iterations, p) {    
  X_after <- matrix(NA_real_, nrow = n_iterations, ncol = n_samples)
  pct_cens <- numeric(n_iterations)
  count <- 1
  while(count <= n_iterations) {     
    random_values <- rlnorm(2L * n_samples, log(mu), log(sigma))
    lod <- quantile(random_values[1:n_samples], p = p)
    X_before <- random_values[(n_samples + 1L):(2L * n_samples)]
    X_after[count, ] <- pmax(X_before, lod)
    delta <- X_before <= lod
    pct_cens[count] <- mean(delta)
    if (pct_cens > 0 && pct_cens < 1 ) count <- count + 1
  }

  Median <- apply(X_after, 1, median)
  Mean <- rowMeans(X_after)
  data.frame(Pct_cens_array=pct_cens, Mean=Mean, Median=Median) 
}

たとえば、タイミングを比較します。

mu=1
sigma=3
n_samples=10L
n_iterations = 1000L
p=0.10
system.time(dset(mu,sigma, n_samples, n_iterations, p))
system.time(dset2(mu,sigma, n_samples, n_iterations, p))

私のマシンでは、3倍のスピードアップがあります。

于 2012-04-10T09:50:03.637 に答える