質問

私は要素確率の配列を持っています、[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では実装されていません。ただし、マルチリアルディストリビューションは、カテゴリカル分布、その目的に使用できます。

>>> import numpy as np
>>> 
>>> def sampleCategory(p):
...     return np.flatnonzero( np.random.multinomial(1,p,1) )[0]
... 
>>> sampleCategory( [0.1,0.5,0.4] )
1
.

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())
.

トリックをするべきです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top