2012-01-23 12 views
7

私は要素の確率の配列を持っています。これは[0.1, 0.2, 0.5, 0.2]としましょう。配列の最大値は1.0です。numpyでランダムな要素を描画する

平易なPythonまたはnumpyを使用して、確率の比例する要素を描画したい:最初の要素は約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]) 

それは動作しますが、それはあまりにも複雑ですが、良い方法がなければなりません。ありがとう。

それがどのように動作する

答えて

9
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 [27]: cutoffs.searchsorted(0.9723114393023948) 
Out[27]: 3 

戻りchoices[idx]、:

In [26]: np.random.uniform(0, cutoffs[-1]) 
Out[26]: 0.9723114393023948 

使用は乱数がcutoffsに挿入されるインデックスを検索します。

0

私はnumpyを一度も使用していませんが、以下のコード(pythonのみ)はあなたが1行で達成したものと同じことをします。私はあなたがそれを望む場合に備えてここに置いています。

非常にc-ishだから非常にpythonicではないことを謝ります。

weight_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 
0

使用bisect

import bisect 
import random 
import numpy 
def draw(probs): 
    cumsum=numpy.cumsum(probs/sum(probs)) 
    return bisect.bisect_left(cumsum, numpy.random.rand()) 

は、トリックを行う必要があります。

1

使用numpy.random.multinomial - あなたがnumpyの中に実装されていないカテゴリ分布からサンプリングしたい

4

最も効率的。しかし、multinomialディストリビューションはcategoricalディストリビューションの一般化であり、その目的のために使用することができます。

>>> 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 
関連する問題