Question

Je veux simuler mourir biaisé N-face?

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
Était-ce utile?

La solution

Un peu de mathématiques ici.

Une matrice régulière donnera à chaque nombre de 1 à 6 avec la même probabilité, à savoir 1/6. Ceci est appelé distribution uniforme (la version discrète de celui-ci, par opposition à la version continue). Ce qui signifie que si une variable est X aléatoire décrivant le résultat d'un rôle unique alors X~U[1,6] -. Signifiant est réparti à parts égales [0,1) contre tous les résultats possibles du jet de dé, 1 à 6

Il est égal à choisir un nombre en divisant [0,1/6) en 6 sections:. [1/6,2/6), [2/6,3/6), [3/6,4/6), [4/6,5/6), [5/6,1), [0,0.2)

Vous demandez une distribution différente, qui est biaisée. La meilleure façon d'y parvenir est de diviser la section 6 pièces [0.2,0.4) en fonction du biais que vous voulez. Donc, dans votre cas, vous voulez le diviser en ce qui suit: [0.4,0.55), 0.55,0.7), [0.7,0.84), [0.84,1), <=>, <=>.

Si vous jetez un oeil à la wikipedia entrée, vous verrez que dans ce cas, la fonction de probabilité cumulée ne sera pas composé de 6 parties de longueur égale, mais plutôt de 6 parties qui diffèrent en longueur selon le biais vous leur avez donné. Même chose pour la distribution de masse.

Retour à la question, en fonction de la langue que vous utilisez, simplement traduire à votre jet de dé. En Python, voici un très sommaire, bien que travaillant, par exemple:

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)

Autres conseils

Plus la langue agnostique, mais vous pouvez utiliser une table de consultation.

A l'aide d'un nombre aléatoire dans la plage 0-1 et rechercher la valeur dans un tableau:

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

Le biais sera proportionnelle.

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

On pourrait utiliser des entiers trop (mieux):

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

It is a little surprising that the np.random.choice answer hasn't been given 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 p option gives "the probabilities associated with each entry in a", where a is np.range(N) for us. "If not given the sample assumes a uniform distribution over all entries in a".

See the recipe for Walker's alias method for random objects with different probablities.
An example, strings A B C 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

cheers
-- denis

Just to suggest a more efficient (and pythonic3) solution, one can use bisect to search in the vector of accumulated values — that can moreover be precomputed and stored in the hope that subsequent calls to the function will refer to the same "bias" (to follow the question parlance).

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 absence of Python 3 accumulate, one can just write a simple loop to compute the cumulative sum.

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

i have created a code for a dictionary giving a event and corresponding probability, it gives back the corresponding key ie the event of that 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top