5

コードを見ると、問題は非常に簡単だと思います。ランダム化された配列があります(配列はランダム化する必要があります。実際の問題には関係しないため、一部のコードは除外されていますが、ランダム化が必要です)。配列内の各要素には、$rules他の条件が満たされた場合(関連性がないためにここでは削除されます)を示唆する「確率」インデックス(ここでは値自体として説明されています)があります。配列要素が「トリガー」される確率(この場合、配列要素のスコアは1ずつ増加します)

コードを考えてみましょう:

<?php
  // Taken from php.net/shuffle user notes
  // Shuffles an array order for the sake of foreach while maintaining
  // key => value associations
  function shuffle_assoc(&$array) {
    $keys = array_keys($array);
    shuffle($keys);
    foreach($keys as $key) {
      $new[$key] = $array[$key];
    }
    return $new;
  }

  $i = 1000000; // How many tests to perform

  // This is my rule list.  Each key is a simple color
  // and each value is a probability represented as a percent
  $rules = array(
    'black' => 20,
    'white' => 10,
    'red' => 40,
    'green' => 5,
    'blue' => 25,
  );

  // Initialize the scores array with all 0's
  // The "outs" will be used when the probability does not
  // occur in any of the rules
  $scores = array('outs' => 0);
  foreach($rules as $k => $v) { 
    $scores[$k] = 0;
  }

  $count = count($rules);

  for($x = 0; $x < $i; $x++) { 
    $rules = shuffle_assoc($rules);

    foreach($rules as $k => $probability) {
      $rand = mt_rand(1,100);
      //$probability = ??; I've tried applying many different operations here to "correct" the probability

      if($rand > $probability) { 
        continue; 
      } else {
        $scores[$k]++;
        continue 2;
      }
    }
    $scores['outs']++;
  }


  foreach($scores as $k => $v) { 
    echo "$k: " . (($v/$i)*100) . "% ($v/$i)\n";
  }

?>

期待される出力(疑似)。パーセンテージはの値に対応していることに注意してください$rules

outs: less than 1% (.../1000000)
black: 20% (.../1000000)
white: 10% (.../1000000)
red: 40% (.../1000000)
green: 5% (.../1000000)
blue: 25% (.../1000000)

出力例:

outs: 30.7128% (307128/1000000)
black: 13.2114% (132114/1000000)
white: 6.3381% (63381/1000000)
red: 29.5247% (295247/1000000)
green: 3.1585% (31585/1000000)
blue: 17.0545% (170545/1000000)

私が試したことと考慮事項:

  • ご覧のとおり、ループ内にコメントアウトされたセクションが$probability = ??あり、各要素内で使用する実際の確率を計算するさまざまなわかりやすい方法を試しました。これには、$count(ルールの数)で遊ぶことも含まれます。そのため、変数が存在し、使用されていません。

  • 明らかに正確である必要はありませんが、より少ない数のセット(1,000回の反復など)で安定した結果が得られることが望ましいです。

  • かなりあいまいになる可能性があります。+/- 5%の分散は、特に反復回数が少ない場合は、私の気持ちを損なうことはありません。ここでは、大きな数の理論が機能するようになることを理解しています。

  • アウトの数は、1%〜2%未満であれば、大した問題ではありません。また、さまざまな方法を使用してアウトを排除して、アウトだけが歪んでいるかどうかを確認しました。興味深いことに、これを行ったときに、20%の分割が発生しました。

  • $rulesさらに、「アウト」では、 100から始まる確率「数値」(つまり、の値)を基本的にブルートフォースすることで、アウトがほとんどなく、適切な分割にかなり近づくことができましたが、できませんでした。正確で最適な方法を見つけるために。毎回、ある色の結果に近づき、小さいながらも目立つスケールで他の色を歪めます。これらの数値には把握しやすい相関関係はなく、一見ランダムに見えましたが、結果が確率と大きな数値でうまく機能したことは明らかです。

これを計算する正確な方法があることを教えてください。それは私を狂わせています。

編集:ループが始まる前に確率のパーセンテージを知る必要なしに、そして追加またはネストされたループ(私が特に必要としたものです、私はその部分ではもっと直接的にすべきだと思います)..ある意味では、各反復は、その特定の反復のプロパティに基づいて動的に確率を引き出すことができます..ここでのすべての答えは非常に貴重でした、これが最終的なコードの私のバージョンです: http: //pastebin.com/eB3TVP1E

4

2 に答える 2

4

結果を正規化し、蓄積するだけで完了です。

私が意味するのは:

  • 配列のすべての項目に与えられたすべての確率を合計して、合計を取得します(これは100あなたの場合ですが、簡単に一般化できます)
  • 合計のすべての確率を除算します

したがって、たとえば:

$rules = array(
    'black' => 20,
    'white' => 10,
    'red' => 40,
    'green' => 5,
    'blue' => 25,
  );

次のように正規化されます:

$rules_norm = array(
    'black' => 0.2,
    'white' => 0.1,
    'red' => 0.4,
    'green' => 0.05,
    'blue' => 0.25,
  );
  • ここで結果を累積して$rules_norm、内部のすべての要素について、前のすべての要素と現在の要素の合計を計算します。

それで:

$rules_norm = array(
    'black' => 0.2,
    'white' => 0.3,
    'red' => 0.7,
    'green' => 0.75,
    'blue' => 1.0,
  );

これで、範囲内の乱数を抽出[0,1)し、結果に応じて増やす要素を選択できます。1つの要素のスコアをインクリメントするには、配列の最初の要素から開始し、次のようにインクリメントします。$rand > $rules_norm[k]

于 2013-01-17T22:27:51.630 に答える
2

コードに実装されたジャックのアイデア(確率の合計が100を超える場合、これは機能しません):

phpフィドル

<?php
  // Taken from php.net/shuffle user notes
  // Shuffles an array order for the sake of foreach while maintaining
  // key => value associations
  function shuffle_assoc(&$array) {
    $keys = array_keys($array);
    shuffle($keys);
    foreach($keys as $key) {
      $new[$key] = $array[$key];
    }
    return $new;
  }

  $i = 1000000; // How many tests to perform

  // This is my rule list.  Each key is a simple color
  // and each value is a probability represented as a percent
  $rules = array(
    'black' => 20,
    'white' => 10,
    'red' => 40,
    'green' => 5,
    'blue' => 25,
  );

  // Initialize the scores array with all 0's
  // The "outs" will be used when the probability does not
  // occur in any of the rules
  $scores = array('outs' => 0);
  foreach($rules as $k => $v) { 
    $scores[$k] = 0;
  }

  $count = count($rules);
//$limits is what Jack called $rules_norm
$limits=array();
$limit=0;
foreach($rules as $k=>$v)
{
    $limit+=$v;
    $limits[$k]=$limit;
}
  for($x = 0; $x < $i; $x++) { 
      $rand = mt_rand(1,100);
foreach($limits as $k=>$v)
{
    if($v>=$rand)
    {
        $scores[$k]++;
        continue(2);
    }

}
    $scores['outs']++;
  }


  foreach($scores as $k => $v) { 
    echo "$k: " . (($v/$i)*100) . "% ($v/$i)\n";
  }

?>
于 2013-01-17T22:47:25.233 に答える