2012-07-07 13 views
32

対応する(指定された)確率に基づいて指定されたランダム値の配列を生成できる簡単な関数を探しています。浮動小数点値を生成するために必要なのですが、スカラーを生成できないはずはありません。私は既存の関数からこれを構築する多くの方法を考えることができますが、明らかにSciPyまたはNumPy関数を見逃したと思います。SciPyまたはNumPyを使用して指定された重み付けで離散ランダム変数を生成

例えば:

>>> values = [1.1, 2.2, 3.3] 
>>> probabilities = [0.2, 0.5, 0.3] 
>>> print some_function(values, probabilities, size=10) 
(2.2, 1.1, 3.3, 3.3, 2.2, 2.2, 1.1, 2.2, 3.3, 2.2) 

注:私はscipy.stats.rv_discreteを見つけましたが、私はそれがどのように動作するか理解していません。具体的には、私は(下)これが何を意味するかもそれが何をすべきか理解していない:

numargs = generic.numargs 
[ <shape(s)> ] = ['Replace with resonable value', ]*numargs 

rv_discreteは、私が使用してすべきかである場合、あなたは「簡単な例を私に提供し、上記の説明でください可能性形 "のステートメント?

答えて

42

離散分布からの描画はnumpyに直接組み込まれています。 この関数はrandom.choiceと呼ばれています(numpyの文書では離散分布を参照することなく見つけるのは難しい)。

elements = [1.1, 2.2, 3.3] 
probabilities = [0.2, 0.5, 0.3] 
np.random.choice(elements, 10, p=probabilities) 
+3

すばらしいです!しかし、正しい構文は次のとおりです。np.random.choice(要素、10、p =リスト(確率)) – Sina

+0

ニース。私は私のオリジナルの質問を投稿した後にこのバージョンが出てきたと思います(私はこれが2013年に来た1.7.0で最初にリリースされたと思います)。 – TimY

+0

非常に良い!リストにキャストせずにも動作するようです:np.random。選択肢(要素、10、p =確率))。 – zeycus

24

ここでは、重み付けされた値を返す比較的単純で、NumPyのdigitize,accumulate、およびrandom_sampleを使用しています。

import numpy as np 
from numpy.random import random_sample 

def weighted_values(values, probabilities, size): 
    bins = np.add.accumulate(probabilities) 
    return values[np.digitize(random_sample(size), bins)] 

values = np.array([1.1, 2.2, 3.3]) 
probabilities = np.array([0.2, 0.5, 0.3]) 

print weighted_values(values, probabilities, 10) 
#Sample output: 
[ 2.2 2.2 1.1 2.2 2.2 3.3 3.3 2.2 3.3 3.3] 

それはこのように動作します:

  1. まず、我々はビンを作成accumulateを使用。
  2. その後、我々は、我々はこれらの数字はに陥るビンかを確認するためにdigitizeを使用random_sample
  3. を使用して(0、および1間)の乱数の束を作成します。
  4. 対応する値を返します。
+1

はい、これは基本的に私が考えていたものですが、ちょうどそのことを行う組み込み関数があると思っていました。それの音から、そのようなものはありません。私は認めなければならない - 私は優雅にそれをしなかっただろう。 - Thanks – TimY

+0

NumPyは 'npy.add.accumulate()'の代わりに 'numpy.cumsum()'を直接提供しています( 'np.add()'はあまり一般的ではないので、 'cumsum ) ')。 – EOL

+0

有用な 'numpy.digitize()'は+1です!しかし、SciPyは実際に質問に直接答える機能を提供しています。私の答えを見てください。 – EOL

3

最も簡単なDIY方法は、確率を累積分布にまとめることです。 このようにして、単位区間を元の確率と等しい長さの部分区間に分割します。今度は、[0,1]上に単一の乱数を生成し、どの区間に着地するかを見てください。

+1

はい、これは基本的に私が考えていたものですが、ちょうどそのことを行う組み込み関数があると思っていました。それの音から、そのようなものはありません。 – TimY

14

あなたは良い方向に進んでいました。組み込みのscipy.stats.rv_discrete()は、離散ランダム変数を直接作成します。ここではそれがどのように動作するかです:

>>> from scipy.stats import rv_discrete 

>>> values = numpy.array([1.1, 2.2, 3.3]) 
>>> probabilities = [0.2, 0.5, 0.3] 

>>> distrib = rv_discrete(values=(range(len(values)), probabilities)) # This defines a Scipy probability distribution 

>>> distrib.rvs(size=10) # 10 samples from range(len(values)) 
array([1, 2, 0, 2, 2, 0, 2, 1, 0, 2]) 

>>> values[_] # Conversion to specific discrete values (the fact that values is a NumPy array is used for the indexing) 
[2.2, 3.3, 1.1, 3.3, 3.3, 1.1, 3.3, 2.2, 1.1, 3.3] 

ので、上記の分布distribvaluesリストからインデックスを返します。

は、より一般的には、rv_discrete()、そのvalues=(…,…)引数の最初の要素に整数値のシーケンスを取り、この場合には、これらの値を返します。特定の(浮動小数点)値に変換する必要はありません。ここでは例を示します。

>>> values = [10, 20, 30] 
>>> probabilities = [0.2, 0.5, 0.3] 
>>> distrib = rv_discrete(values=(values, probabilities)) 
>>> distrib.rvs(size=10) 
array([20, 20, 20, 20, 20, 20, 20, 30, 20, 20]) 

ここで、(整数)入力値は、希望する確率で直接返されます。

+4

注:私はtimeitを実行しようとしましたが、fraxelの純粋にnumpyのバージョンよりも100倍遅いです。何故かそれがなぜ分かったのですか? – TimY

+0

うわー、面白い! 10k要素では、私はさらに300倍の遅さを得ます。私はコードを簡単に見ました。多くのチェックが行われましたが、実行時間の大きな違いを説明できないと思います。私はScipyのコードに深く関わっていないので、違いがどこから来るのか分かりませんでした。 – EOL

+0

@TimY私の素朴な推測は、遅いのは純粋なPythonでより多くの作業が行われていることです。フード)をC言語で書いています(Pythonの数学的/科学的パッケージはCコードをラベリングする傾向があります)。 – dbliss

4

離散確率分布専用の純粋なPythonパッケージLeaを使用することもできます。

>>> distrib = Lea.fromValFreqs((1.1,2),(2.2,5),(3.3,3)) 
>>> distrib 
1.1 : 2/10 
2.2 : 5/10 
3.3 : 3/10 
>>> distrib.random(10) 
(2.2, 2.2, 1.1, 2.2, 2.2, 2.2, 1.1, 3.3, 1.1, 3.3) 

Etvoilà!

関連する問題