algorithm - resueltos - Algoritmo de selección de ruleta
funcion fitness algoritmos geneticos (12)
Aquí hay un poco de código 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
Esta pregunta ya tiene una respuesta aquí:
- Roulette Selection in Genetic Algorithms 12 respuestas
¿Alguien puede proporcionar algún pseudo código para una función de selección de ruleta? ¿Cómo implementaría esto? Realmente no entiendo cómo leer esta notación matemática. Quiero un algoritmo general para esto.
Aquí hay una forma realmente rápida de hacerlo usando la selección de flujo en Java. Selecciona los índices de una matriz usando los valores como pesos. No se necesitan pesos acumulativos debido a las propiedades matemáticas .
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;
}
Esto podría mejorarse aún más usando la suma de Kahan o leyendo a través de los dobles como iterable si la matriz era demasiado grande para inicializarla de una vez.
Bueno, para una ruleta americana, vas a necesitar generar un entero aleatorio entre 1 y 38. Hay 36 números, un 0 y un 00.
Una de las grandes cosas a considerar, sin embargo, es que en la ruleta americana, se pueden hacer muchas apuestas diferentes. Una sola apuesta puede cubrir 1, 2, 3, 4, 5, 6, dos diferentes 12 o 18. Si lo desea, puede crear una lista de listas donde cada número tenga flages adicionales para simplificar eso, o hacerlo todo en la programación .
Si lo estuviera implementando en Python, solo crearía una Tupla de 0, 00 y de 1 a 36 y usaré random.choice () para cada giro.
Esto supone un "Clasificador" de clase que solo tiene una condición de Cadena, un mensaje de Cadena y una doble resistencia. Solo sigue la lógica.
-- Pablo
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;
}
Hay 2 pasos para esto: Primero crea una matriz con todos los valores en la rueda. Puede ser una matriz bidimensional con color o número, o puede elegir agregar 100 a números rojos.
Luego, simplemente genere un número aleatorio entre 0 o 1 (dependiendo de si su idioma comienza a numerar los índices de matriz de 0 o 1) y el último elemento de su matriz.
La mayoría de los idiomas tienen funciones incorporadas de números aleatorios. En VB y VBScript
la función es RND()
. En Javascript es Math.random()
Obtenga el valor de esa posición en la matriz y tenga su número de ruleta al azar.
Nota final : no olvides sembrar tu generador de números aleatorios o obtendrás la misma secuencia de sorteos cada vez que ejecutes el programa.
He elaborado un código Java similar al de Dan Dyer (referenciado anteriormente). Mi ruleta, sin embargo, selecciona un solo elemento basado en un vector de probabilidad (entrada) y devuelve el índice del elemento seleccionado. Habiendo dicho eso, el siguiente código es más apropiado si el tamaño de selección es unitario y si no se supone cómo se calculan las probabilidades y si se permite un valor de probabilidad cero. El código es autónomo e incluye una prueba con 20 giros de rueda (para ejecutar).
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";
}
}
Debajo de una muestra de ejecución para un vector de probabilidad P = [0.2,0.1,0.6,0.1], WheelElements = [0,1,2,3]:
Elemento seleccionado 3, P (s) = 0.1
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 3, P (s) = 0.1
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 1, P (s) = 0.1
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 3, P (s) = 0.1
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 3, P (s) = 0.1
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 0, P (s) = 0.2
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
Elemento seleccionado 2, P (s) = 0.6
El código también prueba una ruleta con cero probabilidad.
Las otras respuestas parecen estar asumiendo que estás tratando de implementar un juego de ruleta. Creo que estás preguntando sobre la selección de la ruleta en los algoritmos evolutivos.
Aquí hay un código de Java que implementa la selección de la ruleta.
Supongamos que tiene 10 elementos para elegir y elige generando un número aleatorio entre 0 y 1. Divide el rango de 0 a 1 en diez segmentos que no se superponen, cada uno proporcional a la aptitud de uno de los diez elementos. Por ejemplo, esto podría verse así:
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
Esta es tu ruleta. Tu número aleatorio entre 0 y 1 es tu giro. Si el número aleatorio es 0.46, entonces el elemento elegido es el ítem 3. Si es 0.92, entonces es el ítem 9.
Me temo que cualquiera que use el generador de números aleatorios integrado en todos los lenguajes de programación debe saber que el número generado no es 100% aleatorio. Debe usarse con precaución.
Primero, genere una matriz de los porcentajes que asignó, digamos p[1..n]
y suponga que el total es la suma de todos los porcentajes.
Luego obtenga un número aleatorio entre 1 y el total, digamos r
Ahora, el algoritmo en lua:
local c = 0
for i = 1,n do
c = c + p[i]
if r <= c then
return i
end
end
Puedes usar una estructura de datos como esta:
Map<A, B> roulette_wheel_schema = new LinkedHashMap<A, B>()
donde A es un número entero que representa un bolsillo de la rueda de la ruleta , y B es un índice que identifica un cromosoma en la población . El número de bolsillos es proporcional a la proporción de aptitud de cada cromosoma:
número de bolsillos = (proporción de aptitud) · (factor de escala)
Luego generamos un azar entre 0 y el tamaño del esquema de selección y con este número aleatorio obtenemos el índice del cromosoma de la ruleta.
Calculamos el error relativo entre la proporción de aptitud de cada cromosoma y la probabilidad de ser seleccionado por el esquema de selección.
El método getRouletteWheel devuelve el esquema de selección basado en la estructura de datos anterior.
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;
}
Yo quería lo mismo y así creé esta clase autónoma de ruleta. Le da una serie de pesos (en forma de una matriz doble) y simplemente devolverá un índice de esa matriz de acuerdo con una selección aleatoria ponderada.
Creé una clase porque puedes obtener una gran velocidad solo haciendo las adiciones acumulativas una vez a través del constructor. Es código C #, ¡pero disfruta de la velocidad y la simplicidad de C!
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;
}
}
Los pesos iniciales dependen de usted. Tal vez podría ser la aptitud de cada miembro, o un valor inversamente proporcional a la posición del miembro en el "top 50". Ej .: 1er lugar = 1.0 ponderación, 2do lugar = 0.5, 3er lugar = 0.333, 4to lugar = 0.25 ponderación etc.
Seudo código de generador de números aleatorios
- agregar uno a un contador secuencial
- obtener el valor actual del contador secuencial
- agregue el valor del contador por el contador de ticks de la computadora o algún otro valor de temporizador de intervalo pequeño
- opcionalmente agregue números de suma, como un número de una pieza externa de hardware como un generador de plasma u otro tipo de fenómenos algo aleatorios
- divide el resultado por un número primo muy grande 359334085968622831041960188598043661065388726959079837 por ejemplo
- obtener algunos dígitos desde el extremo derecho del punto decimal del resultado
- usa estos dígitos como un número aleatorio
Use los dígitos del número aleatorio para crear números aleatorios entre 1 y 38 (o 37 europeos) para la ruleta.