Je suppose que vous avez une liste de probabilités pré-calculée (disons probs
) pour chacun des index de la liste (disons data
) que vous voulez choisir.
En outre, probs
et data
doit évidemment avoir la même longueur et les entrées de probs
doivent être des nombres non négatifs Rajouté à 1
.
Il est une technique simple mais propre à choisir au hasard les index dans data
selon la répartition en probs
qui est connu comme la roue de la roulette . En Python, je crois, il devrait ressembler en quelque sorte comme celui-ci
import random
data = ['A', 'B', 'C', 'D']
probs = [0.2, 0.4, 0.3, 0.1]
def roulette_wheel(probs):
rand = random.random()
for slot, prob in enumerate(probs):
rand -= prob
if rand < 0.0:
return slot
Notez que cela peut être généralisé à une liste de poids non négatifs (qui ne doit pas ajouter jusqu'à 1
) en multipliant rand
par le terme sum(weights)
. Je crois, j'ai d'abord vu cette idée mignonne dans un livre au sujet de la programmation de Pascal il y a quelques années.
Modifier:
Comme MadPhysicist suggéré dans un comment cela peut être beaucoup plus efficace si l'on a besoin de tirer à plusieurs reprises à partir des mêmes données. Dans ce cas, on peut pré-calculer la fonction de distribution cumulative, puis faire une recherche binaire pour l'index tel que cumulative prob. <= rand ~ U(0, 1)
. En Python, cela pourrait par exemple regarder en quelque sorte comme ce qui suit
from random import random
from bisect import bisect_right
def cdf(probs):
cdf = []
total = 0.0
for p in probs:
total += p
cdf.append(total)
return cdf
def roulette_wheel_bisect(cdf):
return bisect_right(cdf, random())
# compute cdf
cumsum = cdf(probs)
# randomly draw 10 indexes
for i in range(0, 10):
print(roulette_wheel_bisect(cumsum))
Disclaimer: Je ne suis pas un programmeur Python par le commerce, de sorte que le code ci-dessus ne doit illustrer l'idée générale. Il peut ne pas être très robuste pour des utilisations pratiques. Vous devriez toujours utiliser une bibliothèque standard bien testée, numpy par exemple, si vous le pouvez.
Edit2:
Je viens d'apprendre que numpy
a numpy.random.choice qui fait exactement ce dont vous avez besoin. Exemple:
from numpy import random
data = ['A', 'B', 'C', 'D']
probs = [0.2, 0.4, 0.3, 0.1]
# randomly draw 10 list elements with replacement
for i in range(0, 10):
print(random.choice(data, p=probs))
double possible de [manière Pythonic pour sélectionner des éléments de la liste avec différentes probabilités] (http://stackoverflow.com/questions/4113307/pythonic-way-to-select-list-elements-with-different -probabilité) – davedwards
Êtes-vous d'accord pour utiliser numpy? –