How can I simulate displaced death in python?

I want to simulate an N-sided offset matrix?

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 
+7
python probability
source share
8 answers

A bit of math here.

A regular cube will give each number 1-6 with equal probability, namely 1/6 . This is called uniform distribution (discrete version, as opposed to continuous version). This means that if X is a random variable describing the result of one role, then X~U[1,6] is X distributed equally over all possible results of a stamp toss, from 1 to 6.

This is equivalent to choosing a number in [0,1) when dividing it into 6 parts: [0,1/6) , [1/6,2/6) , [2/6,3/6) , [3/6,4/6) , [4/6,5/6) , [5/6,1) .

You request another distribution that is biased. The easiest way to achieve this is to divide section [0,1) into 6 parts, depending on which offset you want. Thus, in your case, you would like to divide it into the following: [0,0.2) , [0.2,0.4) , [0.4,0.55) , 0.55,0.7) , [0.7,0.84) , [0.84,1) .

If you look at the Wikipedia entry , you will see that in this case the cumulative probability function will not consist of 6 parts of the same length, but of 6 parts, the length of which differs depending on the offset you gave them. The same goes for mass distribution.

Returning to the question, depending on the language you use, simply translate this back into your die roll. Python provides a very schematic, albeit working, example:

 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) 
+24
source share

More language agnostic, but you can use a lookup table.

Use a random number in the range 0-1 and find the value in the table:

 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 
+9
source share
 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 

The slope will be proportional.

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

You can use integers (better):

 >>> 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 
+5
source share

It's a little surprising that the answer np.random.choice is not listed here.

 from numpy import random def roll(N,bias): '''this function rolls N dimensional die with biasing provided''' return random.choice(np.range(N),p=bias) 

The parameter p gives "the probabilities associated with each entry in a", where a - np.range(N) for us. β€œIf not specified, the selection assumes a uniform distribution across all elements in.”

+2
source share

See the recipe Walker alias method for random objects with different probabilities.
Example: lines ABC or D with probabilities .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 

amuses
- denis

+1
source share

To offer a more efficient (and pythonic3) solution, you can use bisect to search the accumulated values ​​in a vector - it can also be pre-computed and stored in the hope that subsequent calls to the function will refer to the same β€œoffset” (to follow language of the question).

 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 

In the absence of accumulating Python 3, you can simply write a simple loop to calculate the total.

0
source share
 from random import random biases = [0.0,0.3,0.5,0.99] coins = [1 if random()<bias else 0 for bias in biases] 
0
source share

I created the code for the dictionary giving the event and the corresponding probability, it returns the corresponding key, i.e. an event of this probability.

 import random def WeightedDie(Probabilities): high_p = 0 rand = random.uniform(0,1) for j,i in Probabilities.items(): high_p = high_p + i if rand< high_p: return j 
0
source share

All Articles