19

我有一个对象列表(染色体),它有一个属性适合度(chromosome.fitness 介于 0 和 1 之间)

给定这些对象的列表,我如何实现一个返回单个染色体的函数,该染色体被选中的机会与其适应度成正比?也就是说,适应度为 0.8 的染色体被选择的可能性是适应度为 0.4 的染色体的两倍。

我找到了一些 Python 和伪代码实现,但它们对于这个要求来说太复杂了:该函数只需要一个染色体列表。染色体将自己的适应度存储为内部变量。

我已经编写的实现是在我决定允许染色体存储它们自己的适应度之前,所以要复杂得多,并且涉及压缩列表和其他东西。

- - - - - - - - - - - - - - 编辑 - - - - - - - - - - - --------

谢谢 Lattyware。以下功能似乎有效。

def selectOne(self, population):
    max     = sum([c.fitness for c in population])
    pick    = random.uniform(0, max)
    current = 0
    for chromosome in population:
        current += chromosome.fitness
        if current > pick:
            return chromosome
4

6 回答 6

20

使用 numpy.random.choice。

import numpy.random as npr
def selectOne(self, population):
    max = sum([c.fitness for c in population])
    selection_probs = [c.fitness/max for c in population]
    return population[npr.choice(len(population), p=selection_probs)]
于 2018-09-09T10:59:17.297 回答
17

有一种非常简单的方法可以从字典中选择加权随机选项:

def weighted_random_choice(choices):
    max = sum(choices.values())
    pick = random.uniform(0, max)
    current = 0
    for key, value in choices.items():
        current += value
        if current > pick:
            return key

如果您手头没有字典,您可以修改它以适合您的班级(因为您没有提供更多详细信息,或者生成字典:

choices = {chromosome: chromosome.fitness for chromosome in chromosomes}

假设适应度是一个属性。

这是一个修改为采用可迭代染色体的函数的示例,再次做出相同的假设。

def weighted_random_choice(chromosomes):
    max = sum(chromosome.fitness for chromosome in chromosomes)
    pick = random.uniform(0, max)
    current = 0
    for chromosome in chromosomes:
        current += chromosome.fitness
        if current > pick:
            return chromosome
于 2012-04-25T21:29:11.910 回答
2

我更喜欢更少的行:

import itertools

def choose(population):
    bounds = list(itertools.accumulate(chromosome.fitness for chromosome in population))
    pick = random.random() * bounds[-1]
    return next(chromosome for chromosome, bound in zip(population, bounds) if pick < bound)
于 2014-11-29T15:17:57.270 回答
2
def Indvs_wieght(Indvs): # to comput probality of selecting each Indvs by its fitness
    s=1
    s=sum(i.fitness for i in Indvs)
    wieghts = list()
    for i in range(len(Indvs)) :
        wieghts.append(Indvs[i].fitness/s)
    return wieghts  

def select_parents(indvs,indvs_wieghts,number_of_parents=40): # Roulette Wheel Selection method  #number of selected  parent 
    return np.random.choice(indvs,size=number_of_parents,p=indvs_wieghts)
于 2019-11-02T15:32:35.313 回答
1
from __future__ import division
import numpy as np
import random,pdb
import operator

def roulette_selection(weights):
        '''performs weighted selection or roulette wheel selection on a list
        and returns the index selected from the list'''

        # sort the weights in ascending order
        sorted_indexed_weights = sorted(enumerate(weights), key=operator.itemgetter(1));
        indices, sorted_weights = zip(*sorted_indexed_weights);
        # calculate the cumulative probability
        tot_sum=sum(sorted_weights)
        prob = [x/tot_sum for x in sorted_weights]
        cum_prob=np.cumsum(prob)
        # select a random a number in the range [0,1]
        random_num=random.random()

        for index_value, cum_prob_value in zip(indices,cum_prob):
            if random_num < cum_prob_value:
                return index_value


if __name__ == "__main__":
    weights=[1,2,6,4,3,7,20]
    print (roulette_selection(weights))
    weights=[1,2,2,2,2,2,2]
    print (roulette_selection(weights))
于 2016-06-26T06:43:49.500 回答
-1
import random

def weighted_choice(items):
    total_weight = sum(item.weight for item in items)
    weight_to_target = random.uniform(0, total_weight)
    for item in items:
        weight_to_target -= item.weight
        if weight_to_target <= 0:
            return item
于 2012-04-25T21:29:37.613 回答