web-dev-qa-db-fra.com

Algorithme de sélection de roue de roulette

Quelqu'un peut-il fournir un pseudo-code pour une fonction de sélection de roulette? Comment pourrais-je implémenter ceci: je ne comprends pas vraiment comment lire cette notation mathématique. Je veux un algorithme général pour cela.

20
swati

Les autres réponses semblent supposer que vous essayez de mettre en place un jeu de roulette. Je pense que vous parlez de la sélection de la roue de la roulette dans les algorithmes évolutifs.

Voici un code Java qui implémente la sélection de la roue de roulette.

Supposons que vous avez le choix entre 10 éléments et que vous choisissez en générant un nombre aléatoire compris entre 0 et 1. Vous divisez la plage de 0 à 1 en dix segments ne se chevauchant pas, chacun étant proportionnel à l'aptitude de l'un des dix éléments. Par exemple, ceci pourrait ressembler à ceci:

0 - 0.3 is item 1
0.3 - 0.4 is item 2
0.4 - 0.5 is item 3
0.5 - 0.57 is item 4
0.57 - 0.63 is item 5
0.63 - 0.68 is item 6
0.68 - 0.8 is item 7
0.8 - 0.85 is item 8
0.85 - 0.98 is item 9
0.98 - 1 is item 10

Ceci est votre roue de roulette. Votre nombre aléatoire compris entre 0 et 1 correspond à votre tour. Si le nombre aléatoire est 0,46, l'élément choisi est l'élément 3. S'il s'agit de 0,92, il s'agit de l'élément 9.

44
Dan Dyer

Voici un peu de code python:

def roulette_select(population, fitnesses, num):
    """ Roulette selection, implemented according to:
        <http://stackoverflow.com/questions/177271/roulette
        -selection-in-genetic-algorithms/177278#177278>
    """
    total_fitness = float(sum(fitnesses))
    rel_fitness = [f/total_fitness for f in fitnesses]
    # Generate probability intervals for each individual
    probs = [sum(rel_fitness[:i+1]) for i in range(len(rel_fitness))]
    # Draw new population
    new_population = []
    for n in xrange(num):
        r = Rand()
        for (i, individual) in enumerate(population):
            if r <= probs[i]:
                new_population.append(individual)
                break
    return new_population
9
noio

Il y a 2 étapes à cela: Créez d’abord un tableau avec toutes les valeurs sur la roue. Cela peut être un tableau à 2 dimensions avec la couleur et le nombre, ou vous pouvez choisir d’ajouter 100 aux nombres rouges.

Ensuite, générez simplement un nombre aléatoire compris entre 0 et 1 (selon que votre langue commence à numéroter les index de tableau de 0 ou 1) et le dernier élément de votre tableau.

La plupart des langues ont des fonctions de nombres aléatoires intégrées. Dans VB et VBScript, la fonction est RND(). En Javascript c'est Math.random()

Récupérez la valeur de cette position dans le tableau et vous avez votre numéro de roulette aléatoire.

Note finale : n'oubliez pas de définir votre générateur de nombres aléatoires, sinon vous obtiendrez la même séquence de tirages à chaque fois que vous exécuterez le programme.

4
Bork Blatt

Commencez par générer un tableau des pourcentages que vous avez attribués, par exemple p[1..n] et supposons que le total est la somme de tous les pourcentages.

Ensuite, obtenez un nombre aléatoire compris entre 1 et le total, disons r

Maintenant, l'algorithme en lua:

local  c  =  0
for i = 1,n do
    c = c + p[i]
    if r <= c then
        return i
    end
end
4
gray

Voici un moyen très rapide de le faire en utilisant la sélection de flux en Java. Il sélectionne les indices d'un tableau en utilisant les valeurs comme pondérations. Pas de poids cumulatif nécessaire en raison de propriétés mathématiques .

static int selectRandomWeighted(double[] wts, Random rnd) {
    int selected = 0;
    double total = wts[0];

    for( int i = 1; i < wts.length; i++ ) {
        total += wts[i];            
        if( rnd.nextDouble() <= (wts[i] / total)) selected = i;
    }

    return selected;        
}

Cela pourrait être encore amélioré en utilisant sommation Kahan ou en lisant les doublons comme une variable, si le tableau était trop grand pour être initialisé immédiatement.

3
Andrew Mao

Je voulais la même chose et j'ai donc créé cette classe de roulette autonome. Vous lui donnez une série de poids (sous la forme d'un tableau double) et il retournera simplement un index à partir de ce tableau selon un choix aléatoire pondéré.

J'ai créé une classe parce que vous pouvez obtenir une grande vitesse en ne faisant que les additions cumulatives une fois via le constructeur. C'est du code C #, mais appréciez le C comme vitesse et simplicité!

class Roulette
{
    double[] c;
    double total;
    Random random;

    public Roulette(double[] n) {
        random = new Random();
        total = 0;
        c = new double[n.Length+1];
        c[0] = 0;
        // Create cumulative values for later:
        for (int i = 0; i < n.Length; i++) {
            c[i+1] = c[i] + n[i];
            total += n[i];
        }
    }

    public int spin() {
        double r = random.NextDouble() * total;     // Create a random number between 0 and 1 and times by the total we calculated earlier.
        //int j; for (j = 0; j < c.Length; j++) if (c[j] > r) break; return j-1; // Don't use this - it's slower than the binary search below.

        //// Binary search for efficiency. Objective is to find index of the number just above r:
        int a = 0;
        int b = c.Length - 1;
        while (b - a > 1) {
            int mid = (a + b) / 2;
            if (c[mid] > r) b = mid;
            else a = mid;
        }
        return a;
    }
}

Les poids initiaux sont à vous. Peut-être que cela pourrait être l'aptitude de chaque membre, ou une valeur inversement proportionnelle à la position du membre dans les "50 meilleurs". Ex .: 1ère place = 1,0 pondération, 2ème place = 0,5, 3ème place = 0,333, 4ème place = 0,25 pondération etc. etc.

2
Dan W

Ceci suppose que la classe "Classifier" a juste une condition String, un message String et une force double. Suivez juste la logique.

-- Paul

public static List<Classifier> rouletteSelection(int classifiers) {
    List<Classifier> classifierList = new LinkedList<Classifier>();
    double strengthSum = 0.0;
    double probabilitySum = 0.0;

    // add up the strengths of the map
    Set<String> keySet = ClassifierMap.CLASSIFIER_MAP.keySet();
    for (String key : keySet) {
        /* used for debug to make sure wheel is working.
        if (strengthSum == 0.0) {
        ClassifierMap.CLASSIFIER_MAP.get(key).setStrength(8000.0);
        }
         */
        Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
        double strength = classifier.getStrength();
        strengthSum = strengthSum + strength;
    }
    System.out.println("strengthSum: " + strengthSum);

    // compute the total probability. this will be 1.00 or close to it.
    for (String key : keySet) {
        Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
        double probability = (classifier.getStrength() / strengthSum);
        probabilitySum = probabilitySum + probability;
    }
    System.out.println("probabilitySum: " + probabilitySum);

    while (classifierList.size() < classifiers) {
        boolean winnerFound = false;
        double rouletteRandom = random.nextDouble();
        double rouletteSum = 0.0;

        for (String key : keySet) {
            Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
            double probability = (classifier.getStrength() / strengthSum);
            rouletteSum = rouletteSum + probability;
            if (rouletteSum > rouletteRandom && (winnerFound == false)) {
                System.out.println("Winner found: " + probability);
                classifierList.add(classifier);
                winnerFound = true;
            }
        }
    }
    return classifierList;
}
1
Paul

Eh bien, pour une roue de roulette américaine, vous allez avoir besoin de générer un entier aléatoire compris entre 1 et 38. Il y a 36 chiffres, un 0 et un 00.

Un des points importants à prendre en compte, cependant, est que dans la roulette américaine, il existe de nombreux paris différents qui peuvent être faits. Un seul pari peut couvrir 1, 2, 3, 4, 5, 6, deux 12 différents ou 18. Vous pouvez créer une liste de listes dans laquelle chaque numéro comporte des flages supplémentaires pour simplifier cela, ou tout faire dans la programmation. .

Si je l'implémentais en Python, je créerais simplement un tuple de 0, 00 et 1 à 36 et utiliser random.choice () pour chaque rotation.

1
J.T. Hurley

Vous pouvez utiliser une structure de données comme ceci:

Map<A, B> roulette_wheel_schema = new LinkedHashMap<A, B>()

où A est un entier qui représente une poche de la roue de la roulette , et B est un index qui identifie un chromosome dans la population . Le nombre de poches est proportionnel à la condition physique de chaque chromosome:

nombre de poches = (condition physique) · (facteur d'échelle)

Ensuite, nous générons un nombre aléatoire compris entre 0 et la taille du schéma de sélection. Avec ce nombre aléatoire, nous obtenons l’indice du chromosome de la roulette.

Nous calculons l'erreur relative entre la condition physique proportionnelle de chaque chromosome et la probabilité d'être sélectionné par le schéma de sélection.

La méthodegetRouletteWheelrenvoie le schéma de sélection basé sur la structure de données précédente.

private Map<Integer, Integer> getRouletteWheel(
        ArrayList<Chromosome_fitnessProportionate> chromosomes,
        int precision) {

    /*
     * The number of pockets on the wheel
     * 
     * number of pockets in roulette_wheel_schema = probability ·
     * (10^precision)
     */
    Map<Integer, Integer> roulette_wheel_schema = new LinkedHashMap<Integer, Integer>();
    double fitness_proportionate = 0.0D;
    double pockets = 0.0D;
    int key_counter = -1;
    double scale_factor = Math
            .pow(new Double(10.0D), new Double(precision));
    for (int index_cromosome = 0; index_cromosome < chromosomes.size(); index_cromosome++){

        Chromosome_fitnessProportionate chromosome = chromosomes
                .get(index_cromosome);
        fitness_proportionate = chromosome.getFitness_proportionate();
        fitness_proportionate *= scale_factor;
        pockets = Math.rint(fitness_proportionate);
        System.out.println("... " + index_cromosome + " : " + pockets);

        for (int j = 0; j < pockets; j++) {
            roulette_wheel_schema.put(Integer.valueOf(++key_counter),
                    Integer.valueOf(index_cromosome));
        }
    }

    return roulette_wheel_schema;
}
1
d9daniel

J'ai élaboré un code Java similaire à celui de Dan Dyer (mentionné précédemment). Ma roulette, cependant, sélectionne un seul élément en fonction d’un vecteur de probabilité (entrée) et renvoie l’index de l’élément sélectionné . ne présumez pas comment les probabilités sont calculées et si une probabilité nulle est autorisée. Le code est autonome et comprend un test avec 20 tours de roue (à exécuter).

import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.List;
import Java.util.Random;
import Java.util.logging.Level;
import Java.util.logging.Logger;

/**
 * Roulette-wheel Test version.
 * Features a probability vector input with possibly null probability values.
 * Appropriate for adaptive operator selection such as Probability Matching 
 * or Adaptive Pursuit, (Dynamic) Multi-armed Bandit.
 * @version October 2015.
 * @author Hakim Mitiche
 */
public class RouletteWheel {

/**
 * Selects an element probabilistically.  
 * @param wheelProbabilities elements probability vector.
 * @param rng random generator object
 * @return selected element index
 * @throws Java.lang.Exception 
 */
public int select(List<Double> wheelProbabilities, Random rng) 
        throws Exception{

    double[] cumulativeProba = new double[wheelProbabilities.size()];
    cumulativeProba[0] = wheelProbabilities.get(0);
    for (int i = 1; i < wheelProbabilities.size(); i++)
    {
        double proba = wheelProbabilities.get(i);
        cumulativeProba[i] = cumulativeProba[i - 1] + proba;
    }
    int last = wheelProbabilities.size()-1;
     if (cumulativeProba[last] != 1.0)
     {
            throw new Exception("The probabilities does not sum up to one ("
                    + "sum="+cumulativeProba[last]);
     }
    double r = rng.nextDouble();
    int selected = Arrays.binarySearch(cumulativeProba, r);
     if (selected < 0)
        {
            /* Convert negative insertion point to array index.
            to find the correct cumulative proba range index.
            */
            selected = Math.abs(selected + 1);
        }
     /* skip indexes of elements with Zero probability, 
        go backward to matching index*/  
    int i = selected; 
    while (wheelProbabilities.get(i) == 0.0){
        System.out.print(i+" selected, correction");
        i--;
        if (i<0) i=last;
    }
    selected = i;
    return selected;
}



   public static void main(String[] args){

   RouletteWheel rw = new RouletteWheel();
   int rept = 20;
   List<Double> P = new ArrayList<>(4);
   P.add(0.2);
   P.add(0.1);
   P.add(0.6);
   P.add(0.1);
   Random rng = new Random();
   for (int i = 0 ; i < rept; i++){
       try {
           int s = rw.select(P, rng);
           System.out.println("Element selected "+s+ ", P(s)="+P.get(s));
       } catch (Exception ex) {
           Logger.getLogger(RouletteWheel.class.getName()).log(Level.SEVERE, null, ex);
       }
   }
   P.clear();
   P.add(0.2);
   P.add(0.0);
   P.add(0.5);
   P.add(0.0);
   P.add(0.1);
   P.add(0.2);
   //rng = new Random();
   for (int i = 0 ; i < rept; i++){
       try {
           int s = rw.select(P, rng);
           System.out.println("Element selected "+s+ ", P(s)="+P.get(s));
       } catch (Exception ex) {
           Logger.getLogger(RouletteWheel.class.getName()).log(Level.SEVERE, null, ex);
       }
   }
}

 /**
 * {@inheritDoc}
 * @return 
 */
 @Override
 public String toString()
 {
    return "Roulette Wheel Selection";
 }
}

Ci-dessous un exemple d'exécution pour un vecteur proba P = [0.2,0.1,0.6,0,1], WheelElements = [0,1,2,3]:

Élément sélectionné 3, P (s) = 0,1 

Elément sélectionné 2, P (s) = 0.6

Élément sélectionné 3, P (s) = 0,1

Elément sélectionné 2, P (s) = 0.6

Élément sélectionné 1, P (s) = 0,1

Elément sélectionné 2, P (s) = 0.6

Élément sélectionné 3, P (s) = 0,1

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Élément sélectionné 3, P (s) = 0,1

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Élément sélectionné 0, P (s) = 0,2

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Elément sélectionné 2, P (s) = 0.6

Le code teste également une roue de roulette avec une probabilité nulle.

0
hmitcs