我有一系列不同的事件,都有自己的可能性发生。有没有办法计算它们合并的几率,这样我得到的赔率为0,1 2等等。
数学很容易,但计算的数量增长很快,所以我希望有一个功能可以帮助我。
有三个因素的例子:
Event | Yes | No
A | 3% | 97%
B | 4% | 96%
C | 5% | 95%
0发生:$ A [no] * $ B [no] * $ c [no]
1发生:$ A [是] * $ B [否] * $ c [否] + $ A [否] * $ B [是] * $ c [否] + $ A [否] * $ B [no] * $ c [是]
2发生= $ A [是] * $ B [是] * $ c [否] + $ A [是] * $ B [否] * $ c [是] + $ A [否] * $ B [是] * $ c [是]
发生了3次:$ A [是] * $ B [是] * $ c [是]这很容易在php中编写,我的问题是如果我添加更多事件,这是如何扩大规模。只需再添加一两个caclulations的数量,很快代码就会很长。
那么有更简单的方法吗?我会对任何提示或想法表示感谢。
答案 0 :(得分:1)
执行速度很慢。
让我们考虑一个包含5个事件的案例。
发生0事件的几率为:
$no[0] * $no[1] * $no[2] * $no[3] * $no[4]
发生1件事的几率是:
$no[0] * $no[1] * $no[2] * $no[3] * $yes[4] +
$no[0] * $no[1] * $no[2] * $yes[3] * $no[4] +
$no[0] * $no[1] * $yes[2] * $no[3] * $no[4] +
...
在那里你经历了所有的乘法,其中恰好有1'是'选择。
发生2件事的几率是:
$no[0] * $no[1] * $no[2] * $yes[3] * $yes[4] +
$no[0] * $no[1] * $yes[2] * $no[3] * $yes[4] +
$no[0] * $no[1] * $yes[2] * $yes[3] * $no[4] +
...
在那里你经历了所有的乘法,其中恰好有2'是'选择。
这可以概括为:要计算N个事件发生的几率,你要经历所有乘法,其中恰好有N'是'选择。
现在,当你需要计算0到5个事件发生的所有赔率时,你需要经历所有可能的是/否选择组合,并将每个乘法加到$odds[$yesCount]
。
$no[0] * $no[1] * $no[2] * $no[3] * $no[4] ; added to $odds[0]
$no[0] * $no[1] * $no[2] * $no[3] * $yes[4] ; added to $odds[1]
$no[0] * $no[1] * $no[2] * $yes[3] * $no[4] ; added to $odds[1]
$no[0] * $no[1] * $no[2] * $yes[3] * $yes[4] ; added to $odds[2]
$no[0] * $no[1] * $yes[2] * $no[3] * $no[4] ; added to $odds[1]
...
$yes[0] * $yes[1] * $yes[2] * $yes[3] * $yes[4] ; added to $odds[5]
此处共有2**5 = 32
个不同的乘法,或一般2**$eventCount
。
如果我们从0
到2**$eventCount-1
为每个案例分配一个号码,然后使用此号码的位来选择是否&#39,则可以轻松完成所有这些情况;或者没有'每个事件的选择都包含在乘法中,最后将每个乘法结果添加到$odds[$yesCount]
:
// number of events
$eventCount = 5;
// odds of each event happening
$yes = [ 0.10, 0.50, 0.32, 0.66, 0.99 ];
// odds of each event not happening
$no = [];
for ($eventNumber = 0; $eventNumber < $eventCount; $eventNumber++) {
$no[$eventNumber] = 1 - $yes[$eventNumber];
}
// initialize combined $odds to zero
$odds = [];
for ($n = 0; $n <= $eventCount; $n++) {
$odds[$n] = 0;
}
// calculate combined odds
for ($case = 0; $case < 2 ** $eventCount; $case++) {
$multiplication = 1;
$yesCount = 0;
for ($eventNumber = 0; $eventNumber < $eventCount; $eventNumber++) {
if ($case & (1 << $eventNumber)) {
$yesCount++;
$multiplication *= $yes[$eventNumber];
} else {
$multiplication *= $no[$eventNumber];
}
}
$odds[$yesCount] += $multiplication;
}
// show combined odds
for ($n = 0; $n <= $eventCount; $n++) {
echo "Odds of " . $n . " events happening is " . $odds[$n] . "<br>\n";
}
答案 1 :(得分:0)
让我们看看我们在这里真正需要什么。让我们假设,我们有一系列的机会:
$chances = [0.8, 0.3, 0.15];
我们需要的是通过以下计算获得这些结果:
// 0.119
$chance0 = (1-$array[0]) * (1-$array[1]) * (1-$array[2]);
// 0.548
$chance1 = $array[0] * (1-$array[1]) * (1-$array[2]) + (1-$array[0]) * $array[1] * (1-$array[2]) + (1-$array[0]) * (1-$array[1]) * $array[2];
// 0.297
$chance2 = $array[0] * $array[1] * (1-$array[2]) + $array[0] * (1-$array[1]) * $array[2] + (1-$array[0]) * $array[1] * $array[2];
// 0.036
$chance3 = $array[0] * $array[1] * $array[2];
我们真正需要的是基于一个代表一些成功机会的整数,从一个数字池中获取每个非重复组合,并使其余的“反转”,即使它们成为(1 - chance)
< / p>
为实现这一点,我使用了this answer并稍微修改了代码。从上面提到的答案中,我们得到了非重复的机会组合(意思是,如果我们获得2次成功机会,0.8
和0.15
与0.15
和0.8
相同)。接下来,我们使用array_diff
来查看遗留的内容,并假设这些机会失败。但由于那些机会失败,我们需要“反转”它们,用相应的回调调用array_map
。最后一件事是计算array_product
以获得事件发生的机会。
最后我们只有array_sum
所有机会。
class Combinations implements Iterator
{
protected $c = null;
protected $s = null;
protected $n = 0;
protected $k = 0;
protected $pos = 0;
function __construct($s, $k) {
if(is_array($s)) {
$this->s = array_values($s);
$this->n = count($this->s);
} else {
$this->s = (string) $s;
$this->n = strlen($this->s);
}
$this->k = $k;
$this->rewind();
}
function key() {
return $this->pos;
}
function current() {
$r = array();
for($i = 0; $i < $this->k; $i++)
$r[] = $this->s[$this->c[$i]];
return is_array($this->s) ? $r : implode('', $r);
}
function next() {
if($this->_next())
$this->pos++;
else
$this->pos = -1;
}
function rewind() {
$this->c = range(0, $this->k);
$this->pos = 0;
}
function valid() {
return $this->pos >= 0;
}
protected function _next() {
$i = $this->k - 1;
while ($i >= 0 && $this->c[$i] == $this->n - $this->k + $i)
$i--;
if($i < 0)
return false;
$this->c[$i]++;
while($i++ < $this->k - 1)
$this->c[$i] = $this->c[$i - 1] + 1;
return true;
}
}
function getTotalChances($calculateFrom, $successCount)
{
$totalChance = [];
foreach(new Combinations($calculateFrom, $successCount) as $success)
{
$failure = array_map(function($element) {
return (1-$element);
}, array_diff($calculateFrom, $success));
$chance = array_product(array_merge($success, $failure));
$totalChance[] = $chance;
}
return(array_sum($totalChance));
}
$calculateFrom = [0.8, 0.3, 0.15];
var_dump(getTotalChances($calculateFrom, 2));
现在,如果您运行以下内容,您将获得所需:
var_dump(getTotalChances($calculateFrom, 0)); // 0.119
var_dump(getTotalChances($calculateFrom, 1)); // 0.548
var_dump(getTotalChances($calculateFrom, 2)); // 0.297
var_dump(getTotalChances($calculateFrom, 3)); // 0.036