誰かがルーレット選択機能にいくつかの疑似コードを提供できますか?これをどのように実装しますか:この数学表記の読み方が本当にわかりません。これに一般的なアルゴリズムが必要です。
他の答えは、あなたがルーレットゲームを実装しようとしていることを想定しているようです。進化的アルゴリズムにおけるルーレットホイールの選択について質問していると思います。
ここにいくつかのJavaコード があり、ルーレットホイールの選択を実装しています。
選択する10個のアイテムがあり、0〜1の乱数を生成して選択するとします。0〜1の範囲を10個の重複しないセグメントに分割し、それぞれが10個のアイテムの1つの適合度に比例します。たとえば、次のようになります。
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です。
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つのステップがあります。まず、ホイールのすべての値を含む配列を作成します。これは、色と数の2次元配列にすることも、赤の数に100を追加することもできます。
次に、0または1(言語が配列インデックスの番号付けを0または1から開始するかどうかによって異なります)と配列の最後の要素の間の乱数を生成します。
ほとんどの言語には、組み込みの乱数関数があります。 VB and VBScript
では、関数はRND()
です。JavaScriptではMath.random()
です
配列のその位置から値をフェッチすると、ランダムなルーレット番号がわかります。
最後の注記:乱数ジェネレータをシードすることを忘れないでください。そうしないと、プログラムを実行するたびに同じシーケンスの描画が得られます。
最初に、割り当てたパーセンテージの配列を生成します。たとえば、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
これは、Javaでストリーム選択を使用してこれを行う非常に迅速な方法です。値を重みとして使用して、配列のインデックスを選択します。 数学的特性 のため、累積重みは必要ありません。
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 を使用するか、配列が大きすぎて一度に初期化できない場合は、反復可能としてdoubleを読み取ることで、これをさらに改善できます。
同じものが欲しかったので、この自己完結型のルーレットクラスを作成しました。一連の重みを(二重配列の形式で)与えると、重み付けされたランダムピックに従って、その配列からインデックスが返されます。
クラスを作成したのは、コンストラクタを介して1回だけ累積加算を行うだけで大幅に高速化できるためです。それは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位= 1.0ウェイト、2位= 0.5、3位= 0.333、4位= 0.25ウェイトなど。
これは、ストリング条件、ストリングメッセージ、および2倍の強度を持つクラス「Classifier」を想定しています。ただ論理に従ってください。
-ポール
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;
}
さて、アメリカンルーレットホイールの場合、1〜38のランダムな整数を生成する必要があります。36の数字、0、00があります。
ただし、考慮すべき重要なことの1つは、アメリカンルーレットでは、さまざまな賭けが可能であることです。 1つの賭けで1、2、3、4、5、6、2つの異なる12、または18をカバーできます。各番号にフラグを追加してリストのリストを作成するか、プログラミングですべてを行うことができます。 。
Pythonで実装する場合は、0、00、および1〜36のタプルを作成し、各スピンにrandom.choice()を使用します。
次のようなデータ構造を使用できます。
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;
}
私はJava Dan Dyerのコードに似たコード(前述)を作成しました。ただし、ルーレットホイールは、確率ベクトル(入力)に基づいて単一の要素を選択し、インデックスを返しますとは言え、次のコードは、選択サイズが単一で、確率の計算方法を想定しておらず、ゼロ確率値が許可されている場合に、より適切です。コードは自己完結型であり、 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";
}
}
確率ベクトル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
コードはまた、ゼロ確率でルーレットホイールをテストします。