2013-05-18 15 views
5

私は確率ベクトル(長さn)が毎回異なる整数1:nのリストからサンプルするより効率的な方法を探しています。 異なる確率ベクトルから効率的にサンプルする

probs <- matrix(runif(200), nrow = 20) 
answers <- numeric(20) 
for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,]) 

しかし、それは単に1つの番号を毎回取得するために、サンプルを10回呼び出して、それはおそらく最速の方法ではないです:20と試練のn = 10の場合、私は1つが、このようにそれを行うことができます知っています。コードはこのように多くの時間を費やすため、スピードが役立ちます。

多くの感謝!

ルーク

編集:アイデアベンチマークについて私は良い解決策を見つける助け、ローマ、ビッグ感謝。私はこれを答えに移しました。

+1

+1解決策としてランダムロールの回答を追加する必要があります。それはかなりクールなアプローチです!あなたはそれがどのように拡大縮小可能であるかチェックしましたか? –

+0

置換を伴わないRの 'sample'関数*の' prob'引数は、最初の順序包含確率に比例しないことに注意することが重要です。これを保持したいなら、 'sampling' @ CRANパッケージをチェックしてください。 –

+0

入力していただきありがとうございます。 Ferdinand、あなたは私を少し失ってしまいましたが、このサンプルでは長さが1であるため、サンプルは問題ではないと思います(置換の有無にかかわらずサンプリングは同じです)。また、luke2のソリューションは、サンプルを完全に回避します。私はそれを解決策として挙げます。 – lukeholman

答えて

2

ちょうど楽しみのために、もう2つのバージョンを試しました。このサンプリングをどのような規模で行っていますか?私はこれらのすべてがかなり速く、多かれ少なかれ同等であると思います(私はあなたの解決策のためのprobsの作成を含んでいません)。これで他の人がショットを撮るのが大好きです。

library(rbenchmark) 
benchmark(replications = 1000, 
      luke = for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,]), 
      roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)), 
      roman2 = replicate(20, sample(10, 1, prob = runif(10)))) 

    test replications elapsed relative user.self sys.self user.child sys.child 
1 luke   1000 0.41 1.000  0.42  0   NA  NA 
2 roman   1000 0.47 1.146  0.46  0   NA  NA 
3 roman2   1000 0.47 1.146  0.44  0   NA  NA 
1

私が見つけた別のアプローチがあります。これは高速ですが、forループを使ってサンプルを何度も呼び出すだけの速さではありません。私は当初はとても良いと思っていましたが、ベンチマーク()を間違って使っていました。それがどのように動作するか

luke2 = function(probs) { # takes a matrix of probability vectors, each in its own row 
       probs <- probs/rowSums(probs) 
       probs <- t(apply(probs,1,cumsum)) 
       answer <- rowSums(probs - runif(nrow(probs)) < 0) + 1 
       return(answer) } 

はここにあります:写真0から1の大きな確率を数直線上にレイアウト様々な長さの線として確率は小さなものよりも数直線の多くを取るでしょう。あなたは数字のライン上のランダムなポイントを選んで結果を選ぶことができます - 大きな確率は選択される可能性が高くなります。この方法の利点は、関数luke、roman、roman2のようにサンプルを何度も呼び出すのではなく、runif()の1回の呼び出しで必要なすべての乱数をロールバックできることです。しかし、余分なデータ処理が遅くなり、コストがこの利点を相殺する以上のように見えます。

library(rbenchmark) 
probs <- matrix(runif(2000), ncol = 10) 
answers <- numeric(200) 

benchmark(replications = 1000, 
      luke = for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,]), 
      luke2 = luke2(probs), 
      roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)), 
      roman2 = replicate(20, sample(10, 1, prob = runif(10)))) 
       roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)), 
       roman2 = replicate(20, sample(10, 1, prob = runif(10)))) 

    test replications elapsed relative user.self sys.self user.child sys.child 
    1 luke   1000 0.171 1.000  0.166 0.005   0   0 
    2 luke2   1000 0.529 3.094  0.518 0.012   0   0 
    3 roman   1000 1.564 9.146  1.513 0.052   0   0 
    4 roman2   1000 0.225 1.316  0.213 0.012   0   0 

何らかの理由で、何らかの理由でapply()が行を追加すると非常に悪いことが起こります。私はそれがfor()のラッパーだと思ったので、なぜわからないのですか?そして、roman()はluke()と同様に動作するはずです。

+0

'luke2'は呼び出されていません。 'ベンチマーク 'の第3引数は単に関数を定義するだけで、それを実行しません。関数を 'benchmark'呼び出しの外で定義し、代わりに' luke2 = luke2(probs)、roman = ... 'のようなものを使うべきです。 –

+0

Doh、ありがとう。私は今やっていることとローマンが彼をどのように使っていたかの違いを見ています。結局のところそれほど良いことではないことが分かる!私はまだそこには良いソリューションがなければならないように感じています。コールサンプルは何度も最善の方法ではありません。 – lukeholman

関連する問題