私が見つけた別のアプローチがあります。これは高速ですが、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()と同様に動作するはずです。
+1解決策としてランダムロールの回答を追加する必要があります。それはかなりクールなアプローチです!あなたはそれがどのように拡大縮小可能であるかチェックしましたか? –
置換を伴わないRの 'sample'関数*の' prob'引数は、最初の順序包含確率に比例しないことに注意することが重要です。これを保持したいなら、 'sampling' @ CRANパッケージをチェックしてください。 –
入力していただきありがとうございます。 Ferdinand、あなたは私を少し失ってしまいましたが、このサンプルでは長さが1であるため、サンプルは問題ではないと思います(置換の有無にかかわらずサンプリングは同じです)。また、luke2のソリューションは、サンプルを完全に回避します。私はそれを解決策として挙げます。 – lukeholman