Aucune de ces réponses n'est particulièrement claire ou simple.
Voici une méthode claire et simple qui garantit son efficacité.
accumulate_normalize_probabilities prend un dictionnaire p
qui mappe les symboles aux probabilités OU aux fréquences. Il génère une liste utilisable de tuples à partir de laquelle effectuer la sélection.
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
Rendements:
>>> accumulate_normalize_values( { 'a': 100, 'b' : 300, 'c' : 400, 'd' : 200 } )
[('a', 0.1), ('c', 0.5), ('b', 0.8), ('d', 1.0)]
Pourquoi ça marche
L' étape d' accumulation transforme chaque symbole en un intervalle entre lui-même et la probabilité ou la fréquence des symboles précédents (ou 0 dans le cas du premier symbole). Ces intervalles peuvent être utilisés pour sélectionner (et donc échantillonner la distribution fournie) en parcourant simplement la liste jusqu'à ce que le nombre aléatoire dans l'intervalle 0,0 -> 1,0 (préparé plus tôt) soit inférieur ou égal au point final de l'intervalle du symbole actuel.
La normalisation nous libère du besoin de nous assurer que tout a une certaine valeur. Après normalisation, le «vecteur» des probabilités est égal à 1,0.
Le reste du code pour la sélection et la génération d'un échantillon arbitrairement long à partir de la distribution est ci-dessous:
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
Utilisation:
>>> 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()
? Vous construisez la liste principale avec le nombre approprié d'occurrences et en choisissez une. C'est une question en double, bien sûr.