生成的随机加权值 [英] Generate Random Weighted value

查看:101
本文介绍了生成的随机加权值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:我已经重写,希望这个问题我们的目标是更清晰一点

I've rewritten the question in hopes that the goal is a little clearer.

这是这个扩展问题问题这里,我真的很喜欢在在这个答案

This is an extended question to this question here, and I really like the function provided in this answer.

在上面的答案,一个是能够​​设置打一个极端的,具有较高的数字生产越来越低的数字,反之亦然的概率较高的概率。问题是,我必须设置概率3组。这些群体是最低值(LV),最高值(HV)和中间值(MV)。然而,为了简化的要求,我们可以考虑 EVP = HVP = LVP

In the answer above, one is able to set the probability of hitting an extreme, with higher numbers producing a higher probability of getting lower numbers and vice-versa. The issue is that I must set the probabilities for 3 groups. Those groups are Lowest Value (LV), Highest Value (HV), and Middle Value (MV). However, to simplify the request, we can consider EVP=HVP=LVP.

考虑的的范围内,高压/低压应出现基于指定EVP和,因为你通过从每个极端的范围内进展/度可使在范围将增加,或减少的下一个值的概率,基于之间的距离执行副总裁兼MVP。

Given any range, the HV/LV should appear based on the specified EVP and, as you progress/degress through the range from each extreme, the probability of the next value in the range will increase, or decrease, based on the distance between EVP and MVP.

用1-6的例子范围内,1和6为5%(EVP)进行加权,概率传播将是1/6 5%,2/4为15%,和3/4为30%(MVP),合计100%。反过来也应该是可能的,交换执行副总裁兼MVP应该产生如下图的倒数。

Using an example range of 1-6, with 1 and 6 being weighted at 5% (EVP), the probability spread would be 1/6 is 5%, 2/4 is 15%, and 3/4 is 30% (MVP), totalling 100%. The reverse should also be possible, swapping EVP and MVP should produce an inverse of the graph below.

下面是我希望能转达给定的例子预期结果的图像

Here's an image that I hope will convey the results expected from the given example.

中东加权:

奖励:这将是最优秀的,如果我能够设置HVP和LVP分别产生类似于下图的结果(注:此图是不准确的规格上面的)。

Bonus: It would be most excellent if I was able to set HVP and LVP separately producing a result similar to the graph below (Note: The graph is not accurate to specification above).

中东加权(奖金):

中东加权红利图

谢谢!

推荐答案

由于我在家里停留今天因为感冒:(我决定尝试算出这个给你。基本上什么你问的是某种类型的插值。我用最简单的(线性),这些都是我的结果和代码。该代码是那种混乱的,我可能会在未来几天里解决它。

Since I'm stuck at home today because of the flu :( I decided to try and figure this out for you. Essentially what you're asking for is some sort of interpolation. I used the easiest (linear) and these are my results and code. The code is kind of messy and I may fix it in the upcoming days..

<?php

// this function interpolates $a to $b over $steps steps, starting from key $k
// this can be cleaned up significantly
function interpolate($a, $b, $steps, $k) {
    @$per_step = abs($a - $b)/$steps; // suppress warnings in case of division by zero
    if ($a > $b)
        $decreasing = true;
    else
        $decreasing = false;
    $final = array();
    for ($i = 1; $i <= $steps-1; ++$i) {
        if ($decreasing)
            $final[$i+$k] = $a-=$per_step; // linear interpolation
        else
            $final[$i+$k] = $a+=$per_step; // linear interpolation
    }
    return $final;
}

// this function combines probability arrays after the interpolation occurs
// this may happen multiple times, think about 1, 3, 5. interpolation would have to occur
// from 1 -> 2 -> 3, and from 3 -> 4 -> 5.
function interpolateProbabilities ($nodes) {
    $pNodes = array();
    $pNodes = $nodes;
    $keys = array_keys($nodes);
    for ($i = 0; $i < count($keys); $i++) {
        if ($keys[$i+1] - $keys[$i] != 1) {
            $pNodes += interpolate($nodes[$keys[$i]], $nodes[$keys[$i+1]], $keys[$i+1] - $keys[$i], $keys[$i]);
        }
    }
    ksort($pNodes);
    return $pNodes;
}

// this generates a weighed random value and is pretty much copy-pasted from:
// http://w-shadow.com/blog/2008/12/10/fast-weighted-random-choice-in-php/
// it's robust and re-writing it would be somewhat pointless
function generateWeighedRandomValue($nodes) {
    $weights = array_values($nodes);
    $values = array_keys($nodes);
    $count = count($values);
    $i = 0;
    $n = 0;
    $num = mt_rand(0, array_sum($weights));
    while($i < $count) {
        $n += $weights[$i];
        if($n >= $num) {
            break;
           }
        $i++;
       }
    return $values[$i];
}

// two test cases
$nodes = array( 1 => 12, 5 => 22, 9 => 31, 10 => 35); // test 1
$nodes = array( 1 => 22, 3 => 50, 6 => 2, 7 => 16, 10 => 10); // test 2
$export = array();

// run it 1000 times
for ($i = 0; $i < 1000; ++$i) {
    $export[generateWeighedRandomValue(interpolateProbabilities($nodes))]++;
}

// for copy-pasting into excel to test out distribution
print_r($export);

?>



的结果是,我认为,你在寻找什么。
在的情况下:

The results are, I think, exactly what you're looking for. In the case of:

$nodes = array( 1 => 12, 5 => 22, 9 => 31, 10 => 35); // test 1



我得到了以下(最终)数组:

I got the following (final) array:

Array
(
    [5] => 92
    [7] => 94
    [10] => 162
    [8] => 140
    [3] => 71
    [6] => 114
    [2] => 75
    [4] => 69
    [9] => 131
    [1] => 52
)

也就是说, 1 应该发生的时间为12%, 5 22% 9 31%和 10 的时间35%。让图吧:

Namely, 1 should happen 12% of the time, 5 22%, 9 31%, and 10 35% of the time. Lets graph it:

看起来很有希望,但让我们尝试一些疯狂...

It looks promising, but lets try something crazier...

$nodes = array( 1 => 22, 3 => 50, 6 => 2, 7 => 16, 10 => 10); // test 2

在这种情况下, 3 应该发生的时间的50%,并减少急剧进 6 。让我们看看发生了什么!这是阵列(回想起来,我应该整理这些阵列):

In this case, 3 should occur 50% of the time, and steeply decrease into 6. Lets see what happens! This is the array (in retrospect, I should have sorted these arrays):

Array
(
    [4] => 163
    [7] => 64
    [2] => 180
    [10] => 47
    [1] => 115
    [5] => 81
    [3] => 227
    [8] => 57
    [6] => 6
    [9] => 60
)

和让看图片:

它看起来像它的工作原理:)

It looks like it works :)

我希望能够解决你的问题(或至少一点,你在正确的方向)。请注意,我的代码目前拥有多项规定的。也就是说,你所提供的初始节点必须有加起来100%的概率,或者你可能会得到一些靠不住的行为。

I hope I was able to solve your problem (or at least point you in the right direction). Note that my code currently has a number of stipulations. Namely, the initial nodes you provide MUST have probabilities that add up to 100% or you may get some wonky behavior.

此外,该代码是种混乱,但概念是相对简单的。其他一些很酷的东西会尝试,而不是使用线性插值,使用一些其他类型的,这将使你更有趣的结果!

Also, the code is kind of messy but the concepts are relatively simple. Some other cool stuff would be to try and instead of using linear interpolation, use some other kind, which would give you more interesting results!

要避免混淆,我将只显示究竟是怎么算法的工作。
我给PHP中的 $节点阵列在整数=>的形式;频率百分比并最终看起来像阵列(1 => 22,3 => 50,6 => 2,7 => 16,10 = →10),这是试验2 从上面

To avoid confusion I'll just show exactly how the algorithm works. I give PHP a $node array that's in the form of integer => frequency in percentage and ends up looking something like array( 1 => 22, 3 => 50, 6 => 2, 7 => 16, 10 => 10), which is test 2 from above.

<$ C。 $ C>测试2 基本上说要5个控制节点放置在 1,3,6,7,和10 与频率 22%,50%,10% 2%,16%,和。首先,我需要看到确切的其中,我需要做插值。例如,我不需要 6 7 之间做到这一点,但我的需要 1 3 (我们需要插值 2 )和 7 10 (这里我们需要插值 8 9

Test 2 basically says that you want 5 control nodes placed at 1, 3, 6, 7, and 10 with the frequencies of 22%, 50%, 2%, 16%, and 10% respectively. First, I need to see exactly where I need to do the interpolation. For example, I don't need to do it between 6 and 7, but I do need to do it between 1 and 3 (we need to interpolate 2) and 7 and 10 (where we need to interpolate 8 and 9).

1 - > ; 3 (3 - 1) - 1 = 1 步骤,并应在插入键[2] 原数组中为止。值()的 1 - > 3 插值 ABS($ A - $ B)/ $步这将转换为%<绝对值/ code> 1 减去 2 C>,由步骤+ 1 ,在我们的情况下,恰好等于 14 。我们要看看是否该函数增加或减少(你好微积分)。如果该功能越来越我们不断的添加步骤新插数组,直到我们填补所有的空点(如果功能下降,我们减去步骤%值由于我们只需要填写一个点,我们回到 2 =方式> 36 22 + 14 = 36 )。

The interpolation between 1 -> 3 has (3 - 1) - 1 = 1 steps and should be inserted at key[2] in the original array. The value (%) for the 1 -> 3 interpolation is abs($a - $b) / $steps which translates to the absolute value of the % of 1 minus the % of 2, divided by steps + 1 which, in our case, happens to equal 14. We need to see if the function is increasing or decreasing (hello Calculus). If the function is increasing we keep adding the step % to the new interpolation array until we filled all of our empty spots (if the function is decreasing, we subtract the step % value. Since we only need to fill one spot, we return 2 => 36 (22 + 14 = 36).

我们结合阵列,其结果是 (1 => 22 2 => 36,3 =大于50,6 =大于2,7 = GT; 16,10 =大于10)内插的程序 2 ,这是一个百分比值,我们没有明确的声明。

We combine the arrays and the result is (1 => 22, 2 => 36, 3 => 50, 6 => 2, 7 => 16, 10 => 10). The program interpolated 2, which was a percent value that we didn't explicitly declare.

在的情况下, 7 - →10 ,有2个步骤,步骤比例 2 这是从(16-10 )/(3 + 1)= 2 该功能在下降,所以我们需要减去 2 反复,最终插值数组是(8 => 14,9 => 12)。我们将所有的阵列,瞧的。

In the case of 7 -> 10, there are 2 steps, the step percentage is 2 which comes from (16-10) / (3 + 1) = 2. The function is decreasing, so we need to subtract 2 repeatedly. The final interpolated array is (8 => 14, 9 => 12). We combine all of the arrays and voila.

。下图显示了绿色(初始值)和红色(内插值)。您可能需要查看图像看到了整个事情清晰。你会发现,我用±因为算法需要弄清楚,如果我们应该可以增加或减少在一定的时间。

The following image shows the green (initial values) and the red (interpolated values). You may have to "view image" to see the whole thing clearly. You'll notice that I use ± since the algorithm needs to figure out if we're supposed to be increasing or decreasing over a certain period.

这代码或许应该被写在一个更加面向对象的范例。我玩了很多数组键(例如,我需要通过 $氏/ code>,以便更容易,一旦我从返回他们阵列组合插值($一,$ b,$步骤,$ K),因为它们会自动有正确的钥匙。这仅仅是一个PHP的癖好,并在回想起来,我应该有可能与一个更可读的OOP方式开始与去

This code should probably be written in a more OOP paradigm. I play a lot with array keys (for example, I need to pass $k so it's easier to combine arrays once I return them from interpolate($a, $b, $steps, $k) because they automatically have the right keys. This is just a PHP idiosyncrasy and in retrospect, I should have probably went with a more readable OOP approach to begin with.

这是我最后的编辑,我答应:)因为我喜欢用Excel打,这说明百分比如何正常化一旦这些数字被内插。这看的,尤其是考虑到在你的第一张图片是很重要的,你正在展示的是有点的数学是不可能的。

This is my last edit, I promise :) Since I love playing with Excel, this shows how the percentages normalize once the numbers are interpolated. This is important to see, especially considering that in your first picture, what you're showing is somewhat of a mathematical impossibility.

测试1

测试2

Test 1 Test 2

您会发现比例显著减弱,以适应插值。在现实中你的第二幅图看起来更像是这样的:

You'll notice that the percentages dampen significantly to accommodate the interpolation. Your second graph in reality would look more like this:

在该图中,我的体重 1 => 1,5 => 98,10 => 1 ,你看到的缓冲作用的极端。毕竟,百分比,顾名思义要为100!要认识到,阻尼效果是成正比的极端之间的步数,它只是重要

In this graph, I weighed 1 = > 1, 5 => 98, 10 => 1 and you see the extremes of the dampening effect. After all, percentages, by definition have to add up to 100! It's just important to realize that the dampening effect is directly proportional to the number of steps between extremes.

这篇关于生成的随机加权值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆