代码之家  ›  专栏  ›  技术社区  ›  Sam McAfee

遗传算法中的轮盘赌选择

  •  35
  • Sam McAfee  · 技术社区  · 17 年前

    有人能为轮盘赌选择函数提供一些伪代码吗?我将如何实现这一点:

    alt text

    我真的不懂怎么读这个数学符号。我从不接受任何概率或统计数据。

    13 回复  |  直到 9 年前
        1
  •  39
  •   Ian Kemp    12 年前

    我自己做这件事已经有几年了,但是下面的伪代码在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
    

    here 如果你需要进一步的细节。

        2
  •  16
  •   user97370 user97370    14 年前

    已经有很多正确的解决方案,但我认为这段代码更清晰。

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

    此外,如果累积fs,则可以生成更有效的解决方案。

    cfs = [sum(fs[:i+1]) for i in xrange(len(fs))]
    
    def select(cfs):
        return bisect.bisect_left(cfs, random.uniform(0, cfs[-1]))
    

    这不仅速度更快,而且是非常简洁的代码。C++中的STL有一个类似的二分算法,如果你使用的是这种语言。

        3
  •  12
  •   noio    15 年前

    发布的伪代码包含一些不清楚的元素,这增加了生成伪代码的复杂性 孩子 而不是进行纯粹的选择。下面是该伪代码的简单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
    
        4
  •  10
  •   manlio    11 年前

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

    单个选择所需的平均尝试次数为:

    τ=f 最大值 /平均值(f)

    • F 最大值 是人口的最大适应度
    • 平均值(f)是平均适合度

    τ并不明确地依赖于群体中个体的数量(N),但比率可以随N而变化。

    该算法的典型复杂性为O(1) (使用搜索算法的轮盘赌轮选择具有O(N)或O(logn)复杂性)。

    这个过程的概率分布确实与经典轮盘赌选择中的概率分布相同。

    有关更多详细信息,请参阅:

    • 基于随机接受的轮盘赌轮选择 (亚当·利波斯基,多罗塔·利波夫斯卡——2011)
        5
  •  5
  •   noio    15 年前

    以下是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**
    
        6
  •  2
  •   hiddensunset4    15 年前

    从上面的答案中,我得到了下面的答案,这比答案本身更清楚。

    随机(和):随机(12) 通过遍历总体,我们检查以下内容:随机<总和

    让我们选择7作为随机数。

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

        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;
            }
        }
    
        7
  •  1
  •   Kangwon Lee    14 年前

    斯坦福人工智能实验室(Stanford AI lab)的Thrun教授在其Udacity的CS373中还介绍了python中的快速(呃?)重新采样代码。谷歌搜索结果导致以下链接:

    http://www.udacity-forums.com/cs373/questions/20194/fast-resampling-algorithm

        8
  •  1
  •   NickD    14 年前

    这是我最近为轮盘赌选择编写的一个紧凑的java实现,希望能有所帮助。

    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;
    }
    
        9
  •  1
  •   Setu Kumar Basak    10 年前

    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
    
        10
  •  1
  •   Evgenia Karunus    9 年前

    轮盘赌选择 实施: 通常的 随机接受

    通常的

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

    随机接受

    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
    

    您可以选择其中之一,它们将返回相同的结果。


    有用资源:

    http://natureofcode.com/book/chapter-9-the-evolution-of-code -对初学者友好且清晰的遗传算法章节。解释 轮盘赌选择 作为一桶木头字母(你放的越多,选择a的机会就越大, 通常的

    https://en.wikipedia.org/wiki/Fitness_proportionate_selection -描述 随机接受 算法。

        11
  •  0
  •   kiaGh    12 年前
    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;
            }
    
        12
  •  0
  •   Pat Niemeyer    7 年前

    斯威夫特4

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

    例如,给定两元素数组:

    [0.9, 0.1]
    

    weightedRandomIndex()

    下面是一个更完整的测试:

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

    输出:

    0.1 0.09906
    0.1 0.10126
    0.1 0.09876
    0.7 0.70092
    

    这个答案与毛主席在这里的答案基本相同: https://stackoverflow.com/a/15582983/74975

        13
  •  0
  •   Thieu Nguyen    6 年前

    下面是python中的代码。此代码还可以处理适应度的负值。

    from numpy import min, sum, ptp, array 
    from numpy.random import uniform 
    
    list_fitness1 = array([-12, -45, 0, 72.1, -32.3])
    list_fitness2 = array([0.5, 6.32, 988.2, 1.23])
    
    def get_index_roulette_wheel_selection(list_fitness=None):
        """ It can handle negative also. Make sure your list fitness is 1D-numpy array"""
        scaled_fitness = (list_fitness - min(list_fitness)) / ptp(list_fitness)
        minimized_fitness = 1.0 - scaled_fitness
        total_sum = sum(minimized_fitness)
        r = uniform(low=0, high=total_sum)
        for idx, f in enumerate(minimized_fitness):
            r = r + f
            if r > total_sum:
                return idx
    
    get_index_roulette_wheel_selection(list_fitness1)
    get_index_roulette_wheel_selection(list_fitness2)
    
    1. 确保你的健身清单是1D numpy阵列
    2. 将适应度列表缩放到范围[0,1]
    3. 通过1.0-比例适应度列表将最大问题转换为最小问题
    4. 继续在最小化适应度列表中添加元素,直到我们得到的值大于总和
    5. 您可以查看适应度是否很小-->它在最小化适应度方面有更大的价值-->它有更大的机会增加,使价值大于总和。
        14
  •  -1
  •   flavour404    15 年前

    我用C#编写了一个版本,我真的希望确认它确实是正确的:

    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;
    
        }
    
    推荐文章