Il existe un algorithme simple pour choisir un article au hasard, où les articles ont des poids individuels:
1) calculer la somme de tous les poids
2) choisissez un nombre aléatoire égal ou supérieur à 0 et inférieur à la somme des poids
3) parcourez les articles un à la fois, en soustrayant leur poids de votre nombre aléatoire, jusqu'à ce que vous obteniez l'article où le nombre aléatoire est inférieur au poids de cet article
Pseudo-code illustrant ceci:
int sum_of_weight = 0;
for(int i=0; i<num_choices; i++) {
sum_of_weight += choice_weight[i];
}
int rnd = random(sum_of_weight);
for(int i=0; i<num_choices; i++) {
if(rnd < choice_weight[i])
return i;
rnd -= choice_weight[i];
}
assert(!"should never get here");
Cela devrait être simple pour s'adapter à vos conteneurs boost et autres.
Si vos poids sont rarement modifiés mais que vous en choisissez souvent un au hasard, et tant que votre conteneur stocke des pointeurs vers les objets ou compte plus de quelques dizaines d'articles (en gros, vous devez profiler pour savoir si cela aide ou empêche) , puis il y a une optimisation:
En stockant la somme des poids cumulés dans chaque article, vous pouvez utiliser une recherche binaire pour sélectionner l'article correspondant au poids de prélèvement.
Si vous ne connaissez pas le nombre d'éléments dans la liste, il existe un algorithme très soigné appelé échantillonnage de réservoir qui peut être adapté pour être pondéré.
A Monte Carlo method called Russian roulette is used to choose one of these actions
il apparaît dans des seaux lors de la recherche sur Google. "algorithme de roulette russe". Vous pourriez dire que toutes ces personnes ont un nom erroné.Réponse mise à jour à une ancienne question. Vous pouvez facilement le faire en C ++ 11 avec juste le std :: lib:
Sortie sur mon système:
Notez que la plupart du code ci-dessus est uniquement consacré à l'affichage et à l'analyse de la sortie. La génération réelle n'est que de quelques lignes de code. La sortie démontre que les «probabilités» demandées ont été obtenues. Vous devez diviser la sortie demandée par 1,5 car c'est à cela que s'ajoutent les requêtes.
la source
std::discrete_distribution
qu'au lieu destd::piecewise_constant_distribution
cela aurait été encore mieux.Si vos poids changent plus lentement qu'ils ne sont dessinés, C ++ 11
discrete_distribution
sera le plus simple:Notez cependant que le c ++ 11
discrete_distribution
calcule toutes les sommes cumulées lors de l'initialisation. Habituellement, vous voulez cela car cela accélère le temps d'échantillonnage pour un coût O (N) unique. Mais pour une distribution en évolution rapide, cela entraînera un coût de calcul (et de mémoire) élevé. Par exemple, si les poids représentaient le nombre d'éléments et que chaque fois que vous en dessinez un, vous le supprimez, vous souhaiterez probablement un algorithme personnalisé.La réponse de Will https://stackoverflow.com/a/1761646/837451 évite cette surcharge mais sera plus lente à tirer que le C ++ 11 car il ne peut pas utiliser la recherche binaire.
Pour voir qu'il fait cela, vous pouvez voir les lignes pertinentes (
/usr/include/c++/5/bits/random.tcc
sur mon installation Ubuntu 16.04 + GCC 5.3):la source
Ce que je fais lorsque j'ai besoin de peser des nombres, c'est d'utiliser un nombre aléatoire pour le poids.
Par exemple: j'ai besoin de générer des nombres aléatoires de 1 à 3 avec les poids suivants:
Ensuite, j'utilise:
Avec cela, au hasard, il a 10% des probabilités d'être 1, 30% pour être 2 et 60% pour être 3.
Vous pouvez jouer avec lui selon vos besoins.
J'espère que je pourrais vous aider, bonne chance!
la source
Construisez un sac (ou std :: vector) de tous les éléments qui peuvent être sélectionnés.
Assurez-vous que le nombre de chaque élément est proportionnel à votre pondération.
Exemple:
Ayez donc un sac avec 100 articles avec 60 1, 35 2 et 5 3.
Maintenant, triez le sac au hasard (std :: random_shuffle)
Choisissez les éléments du sac de manière séquentielle jusqu'à ce qu'il soit vide.
Une fois vide, re-randomisez le sac et recommencez.
la source
1,2,2
produisant 1 1/3 du temps et 2 2/3. Randomisez le tableau, choisissez le premier, disons un 2, maintenant l'élément suivant que vous choisissez suit la distribution de 1 1/2 du temps et 2 1/2 du temps. Savvy?Choisissez un nombre aléatoire sur [0,1), qui devrait être l'opérateur par défaut () pour un boost RNG. Choisissez l'élément avec la fonction de densité de probabilité cumulée> = ce nombre:
Où random01 () renvoie un double> = 0 et <1. Notez que ce qui précède ne nécessite pas que les probabilités totalisent 1; il les normalise pour vous.
p est juste une fonction affectant une probabilité à un élément de la collection [début, fin). Vous pouvez l'omettre (ou utiliser une identité) si vous avez juste une séquence de probabilités.
la source
J'ai implémenté plusieurs algorithmes aléatoires pondérés simples .
la source