Selezione della roulette negli algoritmi genetici
Domanda
Qualcuno può fornire uno pseudo codice per una funzione di selezione della roulette?Come lo implementerei:
Non capisco davvero come leggere questa notazione matematica.Non ho mai preso in considerazione alcuna probabilità o statistica.
Soluzione
Sono passati alcuni anni da quando l'ho fatto da solo, tuttavia il seguente pseudo codice è stato trovato abbastanza facilmente su google.
for all members of population sum += fitness of this individual end for for all members of population probability = sum of probabilities + (fitness / sum) sum of probabilities += probability end for loop until new population is full do this twice number = Random between 0 and 1 for all members of population if number > probability but less than next probability then you have been selected end for end create offspring end loop
Il sito da cui proviene è reperibile qui se hai bisogno di ulteriori informazioni i dettagli.
Altri suggerimenti
Molte soluzioni giuste già, ma penso che questo codice sia più chiaro.
def select(fs):
p = random.uniform(0, sum(fs))
for i, f in enumerate(fs):
if p <= 0:
break
p -= f
return i
Inoltre, se si accumula la fs, è possibile produrre una soluzione più efficiente.
cfs = [sum(fs[:i+1]) for i in xrange(len(fs))]
def select(cfs):
return bisect.bisect_left(cfs, random.uniform(0, cfs[-1]))
Questo è sia più veloce sia un codice estremamente conciso. STL in C ++ ha un algoritmo di bisection simile disponibile se è la lingua che stai usando.
Lo pseudocodice pubblicato conteneva alcuni elementi poco chiari e aggiunge la complessità di generare prole invece di eseguire la selezione pura. Ecco una semplice implementazione python di quello pseudocodice:
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
Questo si chiama selezione della ruota della roulette tramite accettazione stocastica:
/// \param[in] f_max maximum fitness of the population
///
/// \return index of the selected individual
///
/// \note Assuming positive fitness. Greater is better.
unsigned rw_selection(double f_max)
{
for (;;)
{
// Select randomly one of the individuals
unsigned i(random_individual());
// The selection is accepted with probability fitness(i) / f_max
if (uniform_random_01() < fitness(i) / f_max)
return i;
}
}
Il numero medio di tentativi necessari per una singola selezione è:
&# 964; = f max / avg (f)
- f max è la forma fisica massima della popolazione
- avg (f) è l'idoneità media
# 964; non dipende esplicitamente dal numero di individui nella popolazione (N), ma il rapporto può cambiare con N.
Tuttavia, in molte applicazioni (in cui la forma fisica rimane limitata e la forma fisica media non diminuisce a 0 per aumentare N) & # 964; non aumenta in modo illimitato con N e quindi una complessità tipica di questo algoritmo è O (1) (la selezione della ruota della roulette usando algoritmi di ricerca ha complessità O (N) o O (log N)).
La distribuzione di probabilità di questa procedura è effettivamente la stessa della classica selezione della ruota della roulette.
Per ulteriori dettagli consultare:
- Selezione della ruota della roulette tramite accettazione stocastica (Adam Liposki, Dorota Lipowska - 2011)
Ecco un po 'di codice in C:
// Find the sum of fitnesses. The function fitness(i) should
//return the fitness value for member i**
float sumFitness = 0.0f;
for (int i=0; i < nmembers; i++)
sumFitness += fitness(i);
// Get a floating point number in the interval 0.0 ... sumFitness**
float randomNumber = (float(rand() % 10000) / 9999.0f) * sumFitness;
// Translate this number to the corresponding member**
int memberID=0;
float partialSum=0.0f;
while (randomNumber > partialSum)
{
partialSum += fitness(memberID);
memberID++;
}
**// We have just found the member of the population using the roulette algorithm**
**// It is stored in the "memberID" variable**
**// Repeat this procedure as many times to find random members of the population**
Dalla risposta di cui sopra, ho ottenuto quanto segue, che era più chiaro per me della risposta stessa.
Per fare un esempio:
Casuale (somma) :: Casuale (12) Scorrendo la popolazione, controlliamo quanto segue: random & Lt; sum
Cerchiamo di scegliere 7 come numero casuale.
Index | Fitness | Sum | 7 < Sum
0 | 2 | 2 | false
1 | 3 | 5 | false
2 | 1 | 6 | false
3 | 4 | 10 | true
4 | 2 | 12 | ...
Attraverso questo esempio, il più adatto (Indice 3) ha la più alta percentuale di essere scelto (33%); poiché il numero casuale deve atterrare entro 6 - > 10 e verrà scelto.
for (unsigned int i=0;i<sets.size();i++) {
sum += sets[i].eval();
}
double rand = (((double)rand() / (double)RAND_MAX) * sum);
sum = 0;
for (unsigned int i=0;i<sets.size();i++) {
sum += sets[i].eval();
if (rand < sum) {
//breed i
break;
}
}
Prof. Thrun di Stanford AI lab ha anche presentato un veloce (er?) Codice di ricampionamento in pitone durante il suo CS373 di Udacity. Il risultato della ricerca di Google ha portato al seguente link:
http://www.udacity-forums.com/ cs373 / domande / 20194 / fast-ricampionamento-algoritmo
Spero che questo aiuti
Ecco un'implementazione java compatta che ho scritto di recente per la selezione della roulette, si spera sia utile.
public static gene rouletteSelection()
{
float totalScore = 0;
float runningScore = 0;
for (gene g : genes)
{
totalScore += g.score;
}
float rnd = (float) (Math.random() * totalScore);
for (gene g : genes)
{
if ( rnd>=runningScore &&
rnd<=runningScore+g.score)
{
return g;
}
runningScore+=g.score;
}
return null;
}
Selezione della ruota della roulette in MatLab:
TotalFitness=sum(Fitness);
ProbSelection=zeros(PopLength,1);
CumProb=zeros(PopLength,1);
for i=1:PopLength
ProbSelection(i)=Fitness(i)/TotalFitness;
if i==1
CumProb(i)=ProbSelection(i);
else
CumProb(i)=CumProb(i-1)+ProbSelection(i);
end
end
SelectInd=rand(PopLength,1);
for i=1:PopLength
flag=0;
for j=1:PopLength
if(CumProb(j)<SelectInd(i) && CumProb(j+1)>=SelectInd(i))
SelectedPop(i,1:IndLength)=CurrentPop(j+1,1:IndLength);
flag=1;
break;
end
end
if(flag==0)
SelectedPop(i,1:IndLength)=CurrentPop(1,1:IndLength);
end
end
Based on my research ,Here is another implementation in C# if there is a need for it:
//those with higher fitness get selected wit a large probability
//return-->individuals with highest fitness
private int RouletteSelection()
{
double randomFitness = m_random.NextDouble() * m_totalFitness;
int idx = -1;
int mid;
int first = 0;
int last = m_populationSize -1;
mid = (last - first)/2;
// ArrayList's BinarySearch is for exact values only
// so do this by hand.
while (idx == -1 && first <= last)
{
if (randomFitness < (double)m_fitnessTable[mid])
{
last = mid;
}
else if (randomFitness > (double)m_fitnessTable[mid])
{
first = mid;
}
mid = (first + last)/2;
// lies between i and i+1
if ((last - first) == 1)
idx = last;
}
return idx;
}
Ok, quindi ci sono 2 metodi per selezione della ruota della roulette implementazione: Solito E Accettazione stocastica uno.
Solito algoritmo:
# there will be some amount of repeating organisms here.
mating_pool = []
all_organisms_in_population.each do |organism|
organism.fitness.times { mating_pool.push(organism) }
end
# [very_fit_organism, very_fit_organism, very_fit_organism, not_so_fit_organism]
return mating_pool.sample #=> random, likely fit, parent!
Accettazione stocastica algoritmo:
max_fitness_in_population = all_organisms_in_population.sort_by(:fitness)[0]
loop do
random_parent = all_organisms_in_population.sample
probability = random_parent.fitness/max_fitness_in_population * 100
# if random_parent's fitness is 90%,
# it's very likely that rand(100) is smaller than it.
if rand(100) < probability
return random_parent #=> random, likely fit, parent!
else
next #=> or let's keep on searching for one.
end
end
Puoi scegliere uno dei due, restituiranno risultati identici.
Risorse utili:
http://natureofcode.com/book/chapter-9-the-evolution-of-code - un capitolo chiaro e adatto ai principianti sugli algoritmi genetici.spiega selezione della ruota della roulette come un secchio di lettere di legno (più ne metti, maggiore è la possibilità di scegliere una A, Solito algoritmo).
https://en.wikipedia.org/wiki/Fitness_proportionate_selection - descrive Accettazione stocastica algoritmo.
Questa estensione Swift 4 implementa la selezione casuale ponderata, a.k.a selezione della roulette dai suoi elementi:
public extension Array where Element == Double {
/// Consider the elements as weight values and return a weighted random selection by index.
/// a.k.a Roulette wheel selection.
func weightedRandomIndex() -> Int {
var selected: Int = 0
var total: Double = self[0]
for i in 1..<self.count { // start at 1
total += self[i]
if( Double.random(in: 0...1) <= (self[i] / total)) { selected = i }
}
return selected
}
}
Ad esempio, dato l'array a due elementi:
[0.9, 0.1]
weightedRandomIndex()
restituirà zero il 90% delle volte e un 10% delle volte.
Ecco un test più completo:
let weights = [0.1, 0.7, 0.1, 0.1]
var results = [Int:Int]()
let n = 100000
for _ in 0..<n {
let index = weights.weightedRandomIndex()
results[index] = results[index, default:0] + 1
}
for (key,val) in results.sorted(by: { a,b in weights[a.key] < weights[b.key] }) {
print(weights[key], Double(val)/Double(n))
}
uscita:
0.1 0.09906
0.1 0.10126
0.1 0.09876
0.7 0.70092
Questa risposta è sostanzialmente la stessa della risposta di Andrew Mao qui: https://stackoverflow.com/a/15582983/74975
Ho scritto una versione in C # e sto davvero cercando conferma che sia davvero corretta:
(roulette_selector è un numero casuale che sarà compreso tra 0,0 e 1,0)
private Individual Select_Roulette(double sum_fitness)
{
Individual ret = new Individual();
bool loop = true;
while (loop)
{
//this will give us a double within the range 0.0 to total fitness
double slice = roulette_selector.NextDouble() * sum_fitness;
double curFitness = 0.0;
foreach (Individual ind in _generation)
{
curFitness += ind.Fitness;
if (curFitness >= slice)
{
loop = false;
ret = ind;
break;
}
}
}
return ret;
}