【问题标题】:Weighted random with two weights具有两个权重的随机加权
【发布时间】:2017-08-10 09:56:42
【问题描述】:

在 PHP 中,我需要在 1 到 100 之间选择一个具有两个权重的随机数。这些权重也可以在 1 到 100 之间。如果两个权重都很低,我需要低权重、高权重的随机数。如果一个权重高一个低,或者如果它们都处于中等范围,我希望随机数在 50 左右随机加权。

我不确定解决此问题的最佳方法。任何建议都会很棒!

【问题讨论】:

  • 那么,如果两个权重都很低,1-100 的全范围仍然是可能的,但高值的可能性较小?还是最大值减少了?这感觉像是一种问题,如果您可以更完整地指定它,答案可能会自行提示。
  • 如果一个权重为 10,另一个为 90,那么值的分布是否与一个 40 另一个为 60 或两个权重均为 50 的情况相同?在这种情况下,您可能只需平均这两个数字。那这个数字是什么意思呢?它只是你想要得到的随机数的平均值吗?
  • 如果两者都很低,那么完整范围仍然是可能的,完全正确。我想获得平均值可能是最好的方法。这么明显的答案。谢谢!

标签: php algorithm random


【解决方案1】:

您将需要有关这些权重的更多信息:它们对该索引的概率的权重有多大,以及该概率增加多少会扩散到相邻的索引。

我在这里假设可以提供这些参数,并且概率以正态分布分布。

我建议为每个索引创建一个包含概率的数组。您从每个索引的常量(例如 1)开始,这意味着所有索引都具有相同的被选中概率。

然后一个函数可以对它应用一个权重,给定一个权重应该集中在的索引,权重本身(它增加了该索引的现有“权重”多少),以及散布(标准差的正态分布,生成的概率将散布在周围)。

这是执行此类操作的代码。它的目的不是为了在统计上合理,但我相信它会以令人满意的方式完成这项工作:

function density($x, $median, $stddev) {
    // See https://en.wikipedia.org/wiki/Probability_density_function#Further_details
    return exp(-pow($x - $median,2)/(2*pow($stddev,2))/(2*pi()*$stddev));
}

function homogeneous_distribution($size) {
    return array_fill(0, $size, 1);
}

function add_weight(&$distr, $median, $weight, $spread) {
    foreach ($distr as $i => &$prob) {
        $prob += $weight * density($i, $median, $spread);
    }
}

function random_float() { // between 0 and 1 (exclusive)
    return mt_rand(0, mt_getrandmax() - 1) / mt_getrandmax();
}

function weighted_random($distr) {
    $r = random_float() * array_sum($distr);
    foreach ($distr as $i => $prob) {
        $r -= $prob;
        if ($r < 0) return $i;
    }
}

// Example use with 20 instead of 100.
$distr = homogeneous_distribution(20); // range is 0 .. 19
add_weight($distr, 0, 4, 1); // at index 0, put a weight of 4, spreading with 1
add_weight($distr, 16, 8, 0.5); // at index 16, put a weight of 8, spreading with 0.2

// Print distribution (weights for every index):
echo "DISTRIBUTION:\n";
print_r($distr);

// Get 10 weighted random indexes from this distribution:
echo "RANDOM SAMPLES:\n";
foreach (range(0, 10) as $i) {
    echo weighted_random($distr) . "\n";
}

看到它在rextester.com上运行

【讨论】:

    猜你喜欢
    • 2013-07-10
    • 1970-01-01
    • 2010-12-18
    • 2016-07-04
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多