質問
私は要素確率の配列を持っています、[0.1, 0.2, 0.5, 0.2]
と言ってみましょう。配列は最大1.0の合計です。
プレーンなPythonやnumpyを使用して、確率に比例した要素を描きたい:1つの要素は約10%、2番目の20%、3番目の50%など。
私はこれを思い付きました:
def draw(probs):
cumsum = numpy.cumsum(probs / sum(probs)) # sum up to 1.0, just in case
return len(numpy.where(numpy.random.rand() >= cumsum)[0])
.
それはうまくいきますが、それは畳みえすぎる、より良い方法がなければなりません。ありがとう。
解決
import numpy as np
def random_pick(choices, probs):
'''
>>> a = ['Hit', 'Out']
>>> b = [.3, .7]
>>> random_pick(a,b)
'''
cutoffs = np.cumsum(probs)
idx = cutoffs.searchsorted(np.random.uniform(0, cutoffs[-1]))
return choices[idx]
.
どのように機能するか:
.
In [22]: import numpy as np
In [23]: probs = [0.1, 0.2, 0.5, 0.2]
累積合計を計算する:
.
In [24]: cutoffs = np.cumsum(probs)
In [25]: cutoffs
Out[25]: array([ 0.1, 0.3, 0.8, 1. ])
ハーフオープン間隔[0, cutoffs[-1])
:で均一に分布した乱数を計算する:
.
In [26]: np.random.uniform(0, cutoffs[-1])
Out[26]: 0.9723114393023948
searchsorted ランダムなインデックスを見つける番号はcutoffs
に挿入されます。
.
In [27]: cutoffs.searchsorted(0.9723114393023948)
Out[27]: 3
choices[idx]
を返します。ここで、idx
はそのインデックスです。
他のヒント
numpy.random.multinomial
- 最も効率的な
私はNUMPYを使用しなかったが、私は以下のコードを想定している(Pythonのみ)1行で達成したものと同じことをします。私はあなたがそれを望んでいる場合にはここにそれを置いています。
は非常にC-ishに見えます。非常にPythonicではないことをお詫び申し上げます。
Wiight_totalはあなたのために1になります。
def draw(probs)
r = random.randrange(weight_total)
running_total = 0
for i, p in enumerate(probs)
running_total += p
if running_total > r:
return i
. 使用 bisect
import bisect
import random
import numpy
def draw(probs):
cumsum=numpy.cumsum(probs/sum(probs))
return bisect.bisect_left(cumsum, numpy.random.rand())
.
トリックをするべきです。