Nessuna di queste risposte è particolarmente chiara o semplice.
Ecco un metodo chiaro e semplice che è garantito per funzionare.
accumulate_normalize_probabilities prende un dizionario p
che mappa i simboli a probabilità O frequenze. Produce un elenco utilizzabile di tuple da cui effettuare la selezione.
def accumulate_normalize_values(p):
pi = p.items() if isinstance(p,dict) else p
accum_pi = []
accum = 0
for i in pi:
accum_pi.append((i[0],i[1]+accum))
accum += i[1]
if accum == 0:
raise Exception( "You are about to explode the universe. Continue ? Y/N " )
normed_a = []
for a in accum_pi:
normed_a.append((a[0],a[1]*1.0/accum))
return normed_a
I rendimenti:
>>> accumulate_normalize_values( { 'a': 100, 'b' : 300, 'c' : 400, 'd' : 200 } )
[('a', 0.1), ('c', 0.5), ('b', 0.8), ('d', 1.0)]
Perché funziona
L' accumulo fase di trasforma ciascun simbolo in un intervallo tra se stesso e la probabilità o la frequenza dei simboli precedenti (o 0 nel caso del primo simbolo). Questi intervalli possono essere usati per selezionare (e quindi campionare la distribuzione fornita) semplicemente scorrendo l'elenco fino a quando il numero casuale nell'intervallo 0,0 -> 1,0 (preparato in precedenza) è inferiore o uguale al punto finale dell'intervallo del simbolo corrente.
La normalizzazione ci libera dalla necessità di assicurarci che tutto sommi un certo valore. Dopo la normalizzazione, il "vettore" delle probabilità si somma a 1,0.
Il resto del codice per la selezione e la generazione di un campione arbitrariamente lungo dalla distribuzione è di seguito:
def select(symbol_intervals,random):
print symbol_intervals,random
i = 0
while random > symbol_intervals[i][1]:
i += 1
if i >= len(symbol_intervals):
raise Exception( "What did you DO to that poor list?" )
return symbol_intervals[i][0]
def gen_random(alphabet,length,probabilities=None):
from random import random
from itertools import repeat
if probabilities is None:
probabilities = dict(zip(alphabet,repeat(1.0)))
elif len(probabilities) > 0 and isinstance(probabilities[0],(int,long,float)):
probabilities = dict(zip(alphabet,probabilities)) #ordered
usable_probabilities = accumulate_normalize_values(probabilities)
gen = []
while len(gen) < length:
gen.append(select(usable_probabilities,random()))
return gen
Utilizzo:
>>> gen_random (['a','b','c','d'],10,[100,300,400,200])
['d', 'b', 'b', 'a', 'c', 'c', 'b', 'c', 'c', 'c'] #<--- some of the time
random.choice()
? Si crea l'elenco principale con il numero corretto di occorrenze e si sceglie uno. Questa è una domanda duplicata, ovviamente.