FingeNB FingeNB - 4 months ago 8
PHP Question

Using php to calculate odds for events to happen one or more times with different odds

I got a set of different events, all with their own odds to happen. Is there a way to calculate the odds for them combined, so that I get a the odds for 0, 1 2 and so on to happen.

The math is easy, but the number of calculations grow quick, so I was hoping there was a function that could help me.

Example with three factors :

Event | Yes | No
A | 3% | 97%
B | 4% | 96%
C | 5% | 95%


0 Happening : $A[no] * $ B[no] * $c[no]

1 happening : $A[yes] * $ B[no] * $c[no] + $A[no] * $ B[yes] * $c[no] + $A[no] * $ B[no] * $c[yes]

2 happening = $A[yes] * $ B[yes] * $c[no] + $A[yes] * $ B[no] * $c[yes] + $A[no] * $ B[yes] * $c[yes]

3 happening : $A[yes] * $ B[yes] * $c[yes]

This is easy to write in php, my problem is how this scale up if i add more events. Just adding one more doubles the number of caclulations, and soon the code would be really long.

So is there an easier way to do this? I'll be grateful for any tips or ideas.

Answer

This is quite slow implementation.

Let's consider a case with 5 events.

Odds of 0 events happening is:

$no[0]  * $no[1]  * $no[2]  * $no[3]  * $no[4]

Odds of 1 event happening is:

$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]  +
...

where you go through all multiplications where there is exactly 1 'yes' choice.

Odds of 2 events happening is:

$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]  +
...

where you go through all multiplications where there is exactly 2 'yes' choices.

This can be generalized: To calculate odds of N events happening you go through all multiplications where there is exactly N 'yes' choices.

Now when you need to calculate all odds from 0 to 5 events happening, you need to go through all possible combinations of yes/no choices and add each multiplication to $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]

There are total of 2**5 = 32 different multiplications here, or generally 2**$eventCount.

It is easy to go through all these cases if we assign a number to each case from 0 to 2**$eventCount-1, and then use bits of this number to select whether 'yes' or 'no' choice of each event is included in multiplication, and finally add each multiplication result to $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";
}
Comments