Ninguna de estas respuestas es particularmente clara o simple.
Aquí hay un método claro y simple que garantiza que funcione.
acumulate_normalize_probabilities toma un diccionario p
que asigna símbolos a probabilidades O frecuencias. Produce una lista utilizable de tuplas para hacer la selección.
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
Rendimientos:
>>> accumulate_normalize_values( { 'a': 100, 'b' : 300, 'c' : 400, 'd' : 200 } )
[('a', 0.1), ('c', 0.5), ('b', 0.8), ('d', 1.0)]
Por que funciona
El paso de acumulación convierte cada símbolo en un intervalo entre sí mismo y la probabilidad o frecuencia de los símbolos anteriores (o 0 en el caso del primer símbolo). Estos intervalos se pueden usar para seleccionar (y, por lo tanto, muestrear la distribución proporcionada) simplemente recorriendo la lista hasta que el número aleatorio en el intervalo 0.0 -> 1.0 (preparado anteriormente) sea menor o igual al punto final del intervalo del símbolo actual.
los normalización nos libera de la necesidad de asegurarnos de que todo tenga algún valor. Después de la normalización, el "vector" de probabilidades suma 1.0.
El resto del código para la selección y la generación de una muestra arbitrariamente larga de la distribución se encuentra a continuación:
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
Uso:
>>> 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()
? Construye la lista maestra con el número adecuado de ocurrencias y elige una. Esta es una pregunta duplicada, por supuesto.