Żadna z tych odpowiedzi nie jest szczególnie jasna ani prosta.
Oto jasna, prosta metoda, która na pewno zadziała.
umulate_normalize_probabilities pobiera słownik, p
który odwzorowuje symbole na prawdopodobieństwa LUB częstotliwości. Wyświetla użyteczną listę krotek, z których można dokonać wyboru.
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
Plony:
>>> accumulate_normalize_values( { 'a': 100, 'b' : 300, 'c' : 400, 'd' : 200 } )
[('a', 0.1), ('c', 0.5), ('b', 0.8), ('d', 1.0)]
Dlaczego to działa
Etap akumulacji zamienia każdy symbol w przedział między nim a prawdopodobieństwem lub częstotliwością poprzednich symboli (lub 0 w przypadku pierwszego symbolu). Przedziały te mogą być używane do wybierania z (a tym samym próbkowania dostarczonego rozkładu), po prostu przechodząc przez listę, aż liczba losowa w przedziale 0,0 -> 1,0 (przygotowana wcześniej) będzie mniejsza lub równa punktowi końcowemu interwału bieżącego symbolu.
Normalizacja uwalnia nas od konieczności upewnić, że wszystko sum do pewnej wartości. Po normalizacji „wektor” prawdopodobieństw sumuje się do 1,0.
Reszta kodu dla selekcji i generowanie dowolnie długi próbki z rozkładu jest poniżej:
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))
usable_probabilities = accumulate_normalize_values(probabilities)
gen = []
while len(gen) < length:
gen.append(select(usable_probabilities,random()))
return gen
Stosowanie :
>>> gen_random (['a','b','c','d'],10,[100,300,400,200])
['d', 'b', 'b', 'a', 'c', 'c', 'b', 'c', 'c', 'c']
random.choice()
? Budujesz listę główną z odpowiednią liczbą wystąpień i wybierasz jedno. To oczywiście powielone pytanie.