编辑:我已经重写了这个问题,希望目标更加清晰.
这是对这个问题的扩展问题在这里,我真的很喜欢在所提供的功能,这个答案.
在上面的答案中,人们能够设定击中极端的概率,较高的数字产生较高数字的概率,反之亦然.问题是我必须设置3组的概率.这些组是最低值(LV),最高值(HV)和中间值(MV).但是,为了简化请求,我们可以考虑EVP=HVP=LVP.
给定任何范围,HV/LV应基于指定的EVP出现,并且当您从每个极端的范围内进展/下降时,该范围中下一个值的概率将根据EVP之间的距离增加或减少.和MVP.
使用1-6的示例范围,1和6加权为5%(EVP),概率差为1/6为5%,2/4为15%,3/4为30%(MVP) ),总计100%.反过来也应该是可能的,交换EVP和MVP应该产生下图的反转.
这是一个我希望将传达给定示例预期结果的图像.
中加权:

额外奖励:如果我能够单独设置HVP和LVP产生类似于下图的结果,那将是最优秀的(注意:图表不符合上述规范).
中等加权(奖金):

谢谢!
Dav*_*nco 18
因为我今天因为流感而被困在家里:(我决定尝试为你解决这个问题.基本上你要求的是某种插值.我使用最简单的(线性的)这些是我的结果和代码.代码有点混乱,我可能会在即将到来的日子里修复它.
<?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);
?>
Run Code Online (Sandbox Code Playgroud)
我认为,结果正是您正在寻找的.如果是:
$nodes = array( 1 => 12, 5 => 22, 9 => 31, 10 => 35); // test 1
Run Code Online (Sandbox Code Playgroud)
我得到了以下(最终)数组:
Array
(
[5] => 92
[7] => 94
[10] => 162
[8] => 140
[3] => 71
[6] => 114
[2] => 75
[4] => 69
[9] => 131
[1] => 52
)
Run Code Online (Sandbox Code Playgroud)
也就是说,1应该发生12%的时间,522%,931%和1035%的时间.让它图表:

它看起来很有希望,但让我们尝试更疯狂的东西......
$nodes = array( 1 => 22, 3 => 50, 6 => 2, 7 => 16, 10 => 10); // test 2
Run Code Online (Sandbox Code Playgroud)
在这种情况下,3应该发生50%的时间,并急剧减少到6.让我们看看发生了什么!这是数组(回想起来,我应该对这些数组进行排序):
Array
(
[4] => 163
[7] => 64
[2] => 180
[10] => 47
[1] => 115
[5] => 81
[3] => 227
[8] => 57
[6] => 6
[9] => 60
)
Run Code Online (Sandbox Code Playgroud)
让我们看看图片:

看起来很有效:)
我希望我能够解决你的问题(或者至少指出你正确的方向).请注意,我的代码目前有许多规定.也就是说,您提供的初始节点必须具有高达100%的概率,否则您可能会获得一些不稳定的行为.
此外,代码有点乱,但概念相对简单.其他一些很酷的东西是尝试而不是使用线性插值,使用其他类型,这将给你更有趣的结果!
为了避免混淆,我将只展示算法的工作原理.我给PHP一个$node数组的形式,integer => frequency in percentage最终看起来就像array( 1 => 22, 3 => 50, 6 => 2, 7 => 16, 10 => 10)是test 2从上面来的.
Test 2基本上说你想要5个控制节点分别1, 3, 6, 7, and 10以频率放置22%, 50%, 2%, 16%, and 10%.首先,我要看看到底哪里,我需要做插值.例如,我不需要在6和之间进行7,但我确实需要在1和3(我们需要插值2)7和10(我们需要插值8和9)之间进行.
1 -> 3具有(3 - 1) - 1 = 1步骤之间的插值应插入key[2]原始数组中.值(%对于)1 -> 3插值是abs($a - $b) / $steps它转换到的绝对值%的1减去%的2,除以steps + 1它,对我们来说,恰好相等14.我们需要看看函数是增加还是减少(你好微积分).如果函数增加,我们继续将步骤添加%到新的插值数组,直到我们填充所有空点(如果函数正在减少,我们减去该步骤% value.因为我们只需要填充一个点,我们返回2 => 36(22 + 14 = 36).
我们结合数组,结果是(1 => 22, 2 => 36, 3 => 50, 6 => 2, 7 => 16, 10 => 10).程序内插2,这是我们没有明确声明的百分比值.
在这种情况下7 -> 10,有两个步骤,步骤百分比2来自(16-10) / (3 + 1) = 2.函数正在减少,所以我们需要2重复减去.最终的插值数组是(8 => 14, 9 => 12).我们结合了所有阵列和瞧.
下图显示绿色(初始值)和红色(插值).您可能需要"查看图像"才能清楚地看到整个事物.你会注意到我使用,±因为算法需要弄清楚我们是否应该在一段时间内增加或减少.

这段代码应该用更多的OOP范例编写.我使用数组键玩了很多(例如,我需要传递,$k所以一旦我将它们返回它们就更容易组合数组,interpolate($a, $b, $steps, $k)因为它们会自动拥有正确的键.这只是一个PHP的特性而且回想起来,我应该可以使用它一个更易读的OOP方法.
这是我的最后一次编辑,我保证:)由于我喜欢使用Excel,这显示了一旦插入数字后百分比如何标准化.这一点很重要,特别是考虑到你的第一张照片,你所展示的内容在某种程度上是不可能的.
Test 1
Test 2

您会注意到百分比显着衰减以适应插值.你现实中的第二张图看起来更像是这样的:

在这张图中,我称重1 = > 1, 5 => 98, 10 => 1,你看到了阻尼效果的极端情况.毕竟,根据定义,百分比必须加起来为100!重要的是要意识到阻尼效应与极端之间的步数成正比.
| 归档时间: |
|
| 查看次数: |
4687 次 |
| 最近记录: |