0
<?php

$gender = array(
  'Male'=>30, 
  'Female'=>50,
  'U' =>20);

$total = array_sum(array_values($gender)); 

$current = 0;
$rand = rand(1,$total);

foreach ($gender as $key=>$value)
{
    $current += $value;
    if ($current > $rand)
    {
        echo $key;
        break;
    }
}

?>

目前我正在尝试根据加权百分比生成一个随机值。在这个例子中,男性有 30% 的机会,女性有 50% 的机会,而 U 有 20% 的机会。我感觉代码中的逻辑是错误的,所以我运行了 100 次脚本,通常你会得到 30 个男性,但事实并非如此。有没有更聪明的方法来做到这一点?

4

3 回答 3

2

逻辑基本上是对的,但你应该使用>=比较运算符。要了解为什么这是正确的,假设您只有两个概率相等的选择:

$gender = array('Male' => 1, 'Female' => 1);

$rand将是12$rand1希望何时选择Male. 您的代码将进行测试1 > 1,但它会失败,正确的测试将是1 >= 1,这将成功。

此外,您可能应该进行 100 多次测试来验证随机算法。1,000 可能会产生更具代表性的结果。

于 2013-09-13T01:18:11.097 回答
1

你在正确的路线上。在此处的另一个 StackOverflow 答案中详细介绍了一个很好的算法。

您的实现可能如下所示:

function getWeightedRandom(array $options) {

    // calculate the total of all weights
    $combined = array_sum($options); 

    // generate a random number, where 0 <= $random < $combined
    $random = rand(0, $combined - 1);

    // keep subtracting weights until we drop below an option's weight
    foreach($options as $name => $weight) {
        if($random < $weight) {
            return $name;
        }
        $random -= $weight;
    }
}

// the weights to use for our trials (do not have to add up to 100)
$gender = array(
    'Male' => 30, 
    'Female' => 50,
    'U' => 20);

// used for keeping track of how many of each result
$results = array(
    'Male' => 0, 
    'Female' => 0,
    'U' => 0);

// run a large number of trials to properly test our accuracy
for($i = 0; $i < 100000; $i++) {
    $result = getWeightedRandom($gender);
    $results[$result]++;
}

print_r($results);

输出:

Array
(
    [Male] => 30013
    [Female] => 49805
    [U] => 20182
)

在我看来还不错!

于 2013-09-13T01:18:38.603 回答
0

尝试这个:

/**
 * random by rates
 * @param int $rates 
 * @param int $pow Decimal digits
 */
function randombyrates($rates,$pow){
        $much = pow(10, $pow);
    $max  = array_sum($rates) * $much;
    $rand = mt_rand(1, $max);
    $base = 0;
    foreach ($rates as $k => $v) {
        $min = $base * $much + 1;
        $max = ($base + $v) * $much;
        if ($min <= $rand && $rand <= $max) {
            return $k;
        } else {
            $base += $v;
        }
    }
    return false;
}
$gender = array(
   'Male'=>30, 
   'Female'=>50,
   'U' =>20);
echo randombyrates($gender);

祝你好运!

于 2013-09-13T01:38:18.460 回答