【问题标题】:Algorithm for probability when looping over a randomly ordered array循环随机排序数组时的概率算法
【发布时间】:2013-01-01 14:07:06
【问题描述】:

我认为,通过查看代码,问题非常简单。我有一个随机数组(数组 必须 是随机的,一些代码已被排除,因为它与实际问题无关,但确实需要随机化)。对于数组中的每个元素,都有一个“概率”索引(此处描述为值本身,在 $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% 的平分(即偶数)。

  • 1234563从 100 倒退,但我从来没有找到一个精确的、最佳的方法。每次,我都会更接近一种颜色的结果,这会使其他颜色在一个很小但很明显的范围内倾斜。在这些数字中没有容易理解的相关性,而且似乎是随机的,尽管很明显,结果与概率与大数字相比表现得很好。

告诉我有一种精确的计算方法。快把我逼疯了。

编辑:我有我的代码的最终版本,在下面两个答案的帮助下,在循环开始之前不需要知道概率百分比,也不需要额外或嵌套循环(这是我特别需要的,我想我应该在那部分更直接)..从某种意义上说,每次迭代,您都可以根据特定迭代的属性动态拉动概率..这里的所有答案都是非常宝贵,这是我的最终代码版本:http://pastebin.com/eB3TVP1E

【问题讨论】:

  • 惊喜,有人在发布问题之前进行了研究。我喜欢你。
  • 所以你只需要适当的概率吗?还是我错过了什么?我以前也遇到过这样的事情。
  • 你为什么要洗牌?为什么要为每个键生成一个随机数?你的算法过于复杂了。只需为每个索引选择一个 1 到 100 的随机数,然后找到应该应用哪个规则,即 0-19 为黑色,20-29 为白色,30-69 为红色,70-74 为绿色,75-99 为蓝色.
  • 我考虑过你提到的类似插槽的设置(0-19 黑色,20-29 白色等),但问题是这里可能没有提到其他条件,例如, 通过不相关的条件完全排除白色。这意味着如果随机数落在 23 上,我们就没有结果。
  • 我计算了你当前代码的百分比,它们大致就是你得到的。问题是因为您正在将键和每个键生成随机数,您正在依赖于键的连续条目,以便在选择特定密钥的选择时,键依赖于鼠标依赖事件。一个独立的事件。唯一可行的方法是计算主循环每次迭代中所有规则的正确归一化概率。

标签: php math random probability


【解决方案1】:

在您的代码中实现了 Jack 的想法(如果概率总和 >100,这将不起作用):

php fiddle

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

?>

【讨论】:

  • 这非常有效。我无法让杰克的想法发挥作用,因为我仍在每个foreach 中生成一个随机数,而不是在每次迭代(for)中生成一个随机数,这使得它以一种我什至不想的方式表现得截然不同开始尝试理解。我想补充一点作为参考,虽然当概率总和大于 100% 时,这可能会表现得很奇怪,但当它低于 100% 时,丢失的概率会出现在“出局”中,这在我的具体情况下实际上非常有用。
【解决方案2】:

只需对结果进行归一化,累积它们,然后就完成了。

我的意思是:

  • 对数组中每个项目给出的所有概率求和以获得总数(在您的情况下为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) 范围内提取一个随机浮点数,然后根据结果选择增加哪些元素:要增加一个元素的分数,只需从数组中的第一个元素开始并增加一个元素这样$rand &gt; $rules_norm[k]

【讨论】:

    猜你喜欢
    • 2019-06-30
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 2017-11-26
    • 2013-12-18
    相关资源
    最近更新 更多