N面バイアスダイをシミュレートしたいですか?
def roll(N,bias):
'''this function rolls N dimensional die with biasing provided'''
# do something
return result
>> N=6
>> bias=( 0.20,0.20,0.15,0.15,0.14,0.16,)
>> roll(N,bias)
2
N面バイアスダイをシミュレートしたいですか?
def roll(N,bias):
'''this function rolls N dimensional die with biasing provided'''
# do something
return result
>> N=6
>> bias=( 0.20,0.20,0.15,0.15,0.14,0.16,)
>> roll(N,bias)
2
ここで少し数学。
通常のサイコロは、等しい確率で1から6までの各数字を与えます1/6
。これは、一様分布と呼ばれます(連続バージョンではなく、離散バージョン)。X
つまり、が単一の役割の結果を表す確率変数である場合、 X~U[1,6]
-意味X
はダイスロールのすべての可能な結果(1から6)に対して均等に分配されます。
これは、 6つのセクションに[0,1)
分割しながら番号を選択することと同じです:、、、、、、 。[0,1/6)
[1/6,2/6)
[2/6,3/6)
[3/6,4/6)
[4/6,5/6)
[5/6,1)
偏った別の配布を要求しています。これを実現する最も簡単な方法は、必要な[0,1)
バイアスに応じてセクションを6つの部分に分割することです。したがって、あなたの場合[0,0.2)
、それを次のように分割したいと思うでしょう:、、、、、、
。[0.2,0.4)
[0.4,0.55)
0.55,0.7)
[0.7,0.84)
[0.84,1)
ウィキペディアのエントリを見ると、この場合、累積確率関数は6つの等しい長さの部分ではなく、与えたバイアスに応じて長さが異なる6つの部分で構成されていることがわかります。質量分布についても同様です。
質問に戻り、使用している言語に応じて、これをダイスロールに翻訳し直します。Pythonでは、動作しているとはいえ、非常に大雑把な例を次に示します。
import random
sampleMassDist = (0.2, 0.1, 0.15, 0.15, 0.25, 0.15)
# assume sum of bias is 1
def roll(massDist):
randRoll = random.random() # in [0,1]
sum = 0
result = 1
for mass in massDist:
sum += mass
if randRoll < sum:
return result
result+=1
print(roll(sampleMassDist))
言語に依存しませんが、ルックアップ テーブルを使用できます。
0 ~ 1 の範囲の乱数を使用し、表で値を検索します。
0.00 - 0.20 1
0.20 - 0.40 2
0.40 - 0.55 3
0.55 - 0.70 4
0.70 - 0.84 5
0.84 - 1.00 6
import random
def roll(sides, bias_list):
assert len(bias_list) == sides
number = random.uniform(0, sum(bias_list))
current = 0
for i, bias in enumerate(bias_list):
current += bias
if number <= current:
return i + 1
バイアスは比例します。
>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
6
>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
2
整数も使用できます(より良い):
>>> print roll(6, (10, 1, 1, 1, 1, 1))
5
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 5, 5, 10, 4, 8))
2
>>> print roll(6, (1,) * 6)
4
確率の異なるランダム オブジェクトの Walker のエイリアス メソッドのレシピを参照してください。
例、文字列 ABC または D の確率は .1 .2 .3 .4 --
abcd = dict( A=1, D=4, C=3, B=2 )
# keys can be any immutables: 2d points, colors, atoms ...
wrand = Walkerrandom( abcd.values(), abcd.keys() )
wrand.random() # each call -> "A" "B" "C" or "D"
# fast: 1 randint(), 1 uniform(), table lookup
乾杯
-- デニス
from random import random
biases = [0.0,0.3,0.5,0.99]
coins = [1 if random()<bias else 0 for bias in biases]
より効率的な (および pythonic3) ソリューションを提案するために、 bisectを使用して蓄積された値のベクトルを検索することができます — さらに、関数への後続の呼び出しが同じ「バイアス」を参照することを期待して、事前に計算して保存することができます (質問の用語に従うため)。
from bisect import bisect
from itertools import accumulate
from random import uniform
def pick( amplitudes ):
if pick.amplitudes != amplitudes:
pick.dist = list( accumulate( amplitudes ) )
pick.amplitudes = amplitudes
return bisect( pick.dist, uniform( 0, pick.dist[ -1 ] ) )
pick.amplitudes = None
Python 3 の蓄積がない場合は、単純なループを記述して累積合計を計算できます。