轮盘赌选择算法

时间:2008-11-18 09:56:00

标签: algorithm genetic-algorithm evolutionary-algorithm roulette-wheel-selection

任何人都可以为轮盘选择功能提供一些伪代码吗?我将如何实现这一点:我真的不明白如何阅读这种数学符号。我想要通用算法。

12 个答案:

答案 0 :(得分:44)

其他答案似乎假设您正在尝试实施轮盘赌游戏。我想你在询问进化算法中的轮盘赌选择。

实现轮盘赌选择的

Here is some Java code

假设您有10个项目可供选择,您可以通过生成0到1之间的随机数进行选择。您将范围0到1分成10个不重叠的段,每个段与10个项目之一的适应度成比例。例如,这可能如下所示:

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

这是你的轮盘赌。你的0到1之间的随机数是你的旋转。如果随机数为0.46,则所选项目为项目3.如果为0.92,则为项目9。

答案 1 :(得分:10)

这是一些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

答案 2 :(得分:4)

这有两个步骤:首先创建一个包含方向盘上所有值的数组。这可以是具有颜色和数字的二维数组,或者您可以选择将100添加到红色数字。

然后简单地生成0或1之间的随机数(取决于您的语言是否从0或1开始编号数组索引)和数组中的最后一个元素。

大多数语言都有内置的随机数功能。在VB和VBScript中,函数为RND()。在Javascript中,它是Math.random()

从阵列中的该位置获取值,并获得随机轮盘编号。

最后的注释:不要忘记播种随机数生成器,否则每次运行程序时都会得到相同的绘制序列。

答案 3 :(得分:4)

首先,生成一个您分配的百分比数组,假设为p[1..n]    并假设总数是所有百分比的总和。

然后得到一个介于1到总之间的随机数,让我们说r

现在,lua中的算法:

local  c  =  0
for i = 1,n do
    c = c + p[i]
    if r <= c then
        return i
    end
end

答案 4 :(得分:3)

这是使用Java中的流选择来实现它的一种非常快捷的方法。它使用值作为权重选择数组的索引。由于mathematical properties而无需累积权重。

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

如果数组太大而无法立即初始化,可以使用Kahan summation进行进一步改进,或者将双精度数作为可迭代读取。

答案 5 :(得分:2)

我想要一样,所以创建了这个独立的轮盘类。你给它一系列权重(以双数组的形式),它将根据加权随机选择从该数组中返回一个索引。

我创建了一个类,因为只需通过构造函数执行一次累积添加就可以大大加快速度。它是C#代码,但享受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;
    }
}

初始权重取决于您。也许它可能是每个成员的适应性,或者与成员在“前50名”中的位置成反比的值。例如:第一名= 1.0加权,第二名= 0.5,第三名= 0.333,第四名= 0.25加权等等。

答案 6 :(得分:1)

嗯,对于美国轮盘赌轮,你需要生成1到38之间的随机整数。有36个数字,0和00。

要考虑的一件大事是,在美式轮盘赌中,他们可以做出许多不同的赌注。单个赌注可以涵盖1,2,3,4,5,6,两个不同的12或18。您可能希望创建一个列表列表,其中每个数字都有额外的标志来简化,或者在编程中完成所有操作

如果我在Python中实现它,我只需创建一个0,00和1到36的元组,并为每次旋转使用random.choice()。

答案 7 :(得分:1)

这假定某些类“Classifier”只有String条件,String消息和double strength。只需遵循逻辑。

- 保罗

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

答案 8 :(得分:1)

您可以使用以下数据结构:

Map<A, B> roulette_wheel_schema = new LinkedHashMap<A, B>()

其中A是表示轮盘赌的口袋的整数,B是标识人口中染色体的索引。口袋的数量与每条染色体的适应度成比例:

口袋数=(健康比例)·(比例因子)

然后我们在0和选择模式的大小之间生成一个随机数,用这个随机数我们得到轮盘赌的染色体索引。

我们计算每条染色体的适应度比例与选择方案选择的概率之间的相对误差。

方法 getRouletteWheel 会根据以前的数据结构返回选择方案。

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

答案 9 :(得分:0)

我编写了一个类似于Dan Dyer的Java代码(前面提到过)。然而,我的轮盘赌轮基于概率向量(输入)选择单个元素并返回所选元素的索引。 话虽如此,如果选择大小是单一的,并且如果您不假设如何计算概率并且允许零概率值,则以下代码更合适。代码是独立的,包括一个带有20个轮子旋转的测试(运行)。

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

在proba向量的执行样本P = [0.2,0.1,0.6,0.1]下面, WheelElements = [0,1,2,3]:

元素选择3,P(s)= 0.1

元素选择2,P(s)= 0.6

元素选择3,P(s)= 0.1

元素选择2,P(s)= 0.6

元素选择1,P(s)= 0.1

元素选择2,P(s)= 0.6

元素选择3,P(s)= 0.1

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择3,P(s)= 0.1

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择0,P(s)= 0.2

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

元素选择2,P(s)= 0.6

该代码还测试了概率为零的轮盘赌。

答案 10 :(得分:-4)

我担心在所有编程语言中使用内置随机数生成器的人都必须知道生成的数字不是100%随机的。所以应该谨慎使用。

答案 11 :(得分:-5)

随机数生成器伪代码

  • 将一个添加到顺序计数器
  • 获取顺序计数器的当前值
  • 通过计算机滴答计数或其他一些小间隔计时器值添加计数器值
  • 可选择添加附加编号,例如来自外部硬件的数字,如等离子发生器或其他某种类型的随机现象
  • 将结果除以非常大的素数 359334085968622831041960188598043661065388726959079837例如
  • 从结果小数点的最右边获取一些数字
  • 将这些数字用作随机数

使用随机数位数为轮盘赌创建1到38(或37欧洲)之间的随机数。