Pergunta

Alguém pode fornecer algum código pseudo para uma função de seleção de roleta? Como eu poderia implementar esta:

text alt

Eu realmente não entendo como ler esta notação matemática. Eu nunca teve qualquer probabilidade ou estatísticas.

Foi útil?

Solução

Tem sido alguns anos desde que eu fiz isso, no entanto o seguinte código pseudo foi encontrado com bastante facilidade no 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

O site de onde veio isso pode ser encontrada aqui Se precisar de mais detalhes.

Outras dicas

Muitas das soluções corretas já, mas acho que este código é mais clara.

def select(fs):
    p = random.uniform(0, sum(fs))
    for i, f in enumerate(fs):
        if p <= 0:
            break
        p -= f
    return i

Além disso, se você acumular os fs, você pode produzir uma solução mais eficiente.

cfs = [sum(fs[:i+1]) for i in xrange(len(fs))]

def select(cfs):
    return bisect.bisect_left(cfs, random.uniform(0, cfs[-1]))

Isto é tanto mais rápido e é código extremamente conciso. STL em C ++ tem um algoritmo bisection similar disponível se esse é o idioma que você está usando.

O pseudocódigo postou continha alguns elementos pouco claros, e acrescenta a complexidade de gerar prole em vez de realizar seleção pura. Aqui está uma implementação simples python desse pseudo-código:

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

Este é chamado de seleção roleta rodas através de aceitação estocástica:

/// \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;
  }   
}

O número médio de tentativas necessárias para uma única seleção é:

t = f max / média (f)

  • f max é a aptidão máxima da população
  • avg (f) é a aptidão média

t não depende explicitamente do número de indivíduos na população (N), mas a razão pode mudar com N.

No entanto, em muitas aplicações (onde os restos da aptidão limitada e a aptidão média não diminui a 0 para aumentar a N) t não aumenta unboundedly com N e, assim, uma complexidade típico deste algoritmo é O (1 ) (selecção roleta usando algoritmos de busca tem O (N) ou O (log N) complexidade).

A distribuição de probabilidade de este processo é, de facto o mesmo como na selecção de roleta rodas clássica.

Para mais detalhes veja:

  • seleção roleta rodas através de aceitação estocástica (Adam Liposki, Dorota Lipowska - 2011)

Aqui está um código em 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**

A partir da resposta acima, eu tenho o seguinte, que era mais claro para mim que a própria resposta.

Para dar um exemplo:

Aleatório (soma) :: aleatório (12) Iteração através da população, verificamos o seguinte: aleatória

Vamos escolheu 7 como o número aleatório.

Index   |   Fitness |   Sum |   7 < Sum
0       |   2   |   2       |   false
1       |   3   |   5       |   false
2       |   1   |   6       |   false
3       |   4   |   10      |   true
4       |   2   |   12      |   ...

Através deste exemplo, os mais aptos (Índice 3) tem a maior percentagem de ser escolhido (33%); como o número aleatório só tem de terra dentro de 6> 10, e será escolhido.

    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 de Stanford AI laboratório também apresentou um rápido (er?) Re-amostragem código em python durante sua CS373 de Udacity. resultado da pesquisa Google levou ao seguinte link:

http://www.udacity-forums.com/ cs373 / perguntas / 20194 / fast-reamostragem-algoritmo

Espero que isso ajude

Aqui está uma implementação Java compacto eu escrevi recentemente para a seleção roleta, esperançosamente de uso.

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;
}

Roulette Seleção Roda em 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, de forma que há métodos para 2 selecção roleta execução:. habitual e estocástico Aceitação um

Usual 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!

Stochastic Aceitação 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

Você pode escolher qualquer um, estarão retornando resultados idênticos.


Recursos úteis:

http://natureofcode.com/book/chapter-9 -a-evolution-de-código - um capítulo iniciante-friendly e clara em algoritmos genéticos. explica seleção roleta como um balde de letras de madeira (o mais como você colocar em - a grande é a chance de escolher um A, Usual algoritmo).

https://en.wikipedia.org/wiki/Fitness_proportionate_selection - descreve Stochastic Aceitação algoritmo.

Este Swift 4 fortes implementos de extensão matriz ponderada de selecção aleatória, a.k.a selecção da roleta a partir dos seus elementos:

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
    }
}

Por exemplo, dada a disposição de dois elementos:

[0.9, 0.1]

weightedRandomIndex() retornará zero 90% do tempo e um 10% do tempo.

Aqui é um teste mais 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))
}

saída:

0.1 0.09906
0.1 0.10126
0.1 0.09876
0.7 0.70092

Esta resposta é basicamente o mesmo que a resposta de Andrew Mao aqui: https://stackoverflow.com/a/15582983/74975

Eu escrevi uma versão em C # e estou olhando realmente para a confirmação de que é realmente correto:

(roulette_selector é um número aleatório que será na gama de 0.0 a 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;

    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top