Is there a built in function (or a function in one of the standard packages) that allows you to compute the probability of exactly one event occurring out of some known set of probabilities for N independent events?

Ideally what I'd want is something with a signature like:

Pr[independentProbabilities__] := ... 

To give an example, suppose I have a process that produces a letter from the set {A, B, C, D, X} with probabilities:

$$P(A) = 0.1\text{, } P(B) = 0.22\text{, } P(C) = 0.17\text{, } P(D) = 0.28$$

what is the probability that exactly one of the possibilities (A, B, C, or D) occurs?

  • 3
    $\begingroup$ I don't really understand the question. If you draw one letter, then of course exactly one will occur. Also, those probabilities you gave don't sum up to 1, is the remaining associated with X? $\endgroup$
    – Szabolcs
    Mar 15, 2012 at 7:16
  • $\begingroup$ One possible interpretation is that $N$ independent draws are made from the given distribution. The probability that exactly one of $A, \ldots, D$ occurs is the chance that $X$ occurs exactly $N-1$ times: that's given by the binomial probability With[{p = Plus @@ independentProbabilities}, N p(1-p)^(N-1)]. But this is so simple I wonder whether it is the intended interpretation... $\endgroup$
    – whuber
    Mar 15, 2012 at 16:16
  • $\begingroup$ @whuber - In this particular case, you are correct - but that is more a flaw in my example. What I'm looking for is a functional expansion of the identity: P(A ^ B ^ C) == (P(A)*(1-P(B))*(1-P(C)) + ((1-P(A))*P(B)*(1-P(C))) + ((1-P(A))*(1-P(B))*P(C)). $\endgroup$
    – LBushkin
    Mar 16, 2012 at 5:50
  • $\begingroup$ If by "^" you mean conjunction, then that identity appears to be incorrect or meaningless. I doubt it refers to a single outcome of the process, because then "A^B^C" is the empty set (since outcomes A, B, and C are mutually exclusive). If it refers to a sequence of three independent outcomes, we could interpret the lhs as the probability of the sequence ABC, but the rhs gives the sum of the chances that A occurs first or B second or C third; it is going to be greater than the lhs, because it includes outcomes of the form AXX, XBX, XXC, ABX, etc. So what did you really mean to write? $\endgroup$
    – whuber
    Mar 16, 2012 at 13:59
  • $\begingroup$ @whuber: Let me see if I can put it a different way. If I told that you that there is a 10% chance that it will rain tomorrow, a 22% chance that there will be a sale at Macy's, and a 17% chance that your flight will be delayed, could you tell me the probability of exactly one and only one of those things occurring? $\endgroup$
    – LBushkin
    Mar 17, 2012 at 5:59

2 Answers 2

Pr[independentProbabilities__] := 
 Block[{x, len = Length[{independentProbabilities}]},
  Probability[Sum[x[i], {i, len}] == 1, 
   Thread[x /@ Range[len] \[Distributed] 
     BernoulliDistribution /@ {independentProbabilities}]]


In[19]:= Pr[0.1, 0.22, 0.17, 0.28]

Out[19]= 0.414007

Or, doing the math

PrV2[independentProbabilities__] := 
 Total[Times @@@ ((1 - 
        Length[{independentProbabilities}]]) + 
     DiagonalMatrix[2 {independentProbabilities} - 1])]

This reply contributes a theoretical analysis of the question and provides a Mathematica solution that scales well for large lists of probabilities.

(Questions have appeared on our sister site, stats.stackexchange.com, involving arrays of up to a million probabilities, so this is of more than just academic interest.)

Theoretical solution

In clarifying comments to the question we learn that the argument independentProbabilities is a list of chances of independent events. By definition, when events $A$ and $B$ are independent, their probabilities multiply: $\Pr(A \cap B) = \Pr(A)\Pr(B)$. Moreover, (a) $A$ is also independent of the complement of $B$ ($B$ not happening) and (b) the probability of the complement of $B$ equals $1-\Pr(B)$. Finally, when events $E$ and $F$ cannot both happen, they are mutually exclusive and, to find the chance that at least one of them happens, their probabilities add: $\Pr(E \cup F) = \Pr(E) + \Pr(F)$.

From these (axiomatic) properties of probability we conclude that the chance of exactly one of independent events $A, B, \ldots, Z$ happening can be obtained by finding the chance that only $A$ happens, adding to that the chance that only $B$ happens, ..., etc.

The formula therefore is of the form

$$\eqalign{ \Pr(\text{Exactly one of }A,B,C,\ldots,Y,Z) &= \Pr(A)(1-\Pr(B))\cdots(1-\Pr(Z)) \\ &+ (1-\Pr(A))\Pr(B)(1-\Pr(C))\cdots(1-\Pr(Z)) \\ &+ (1-\Pr(A))\cdots(1-\Pr(Y))\Pr(Z). }$$

Mathematica implementation

An elegant way to compute this from an array of these probabilities exploits polynomial multiplication:

pr[p_List] := Block[{u, x = 1 - p, n = Length[p]},
  Coefficient[Times @@ (u + x), u] - n Times @@ x 

This works correctly even when an empty list is presented (the probability that exactly one of no events occurs should be 0).

Efficiency is an issue with some solutions


data = RandomReal[{0, 1}, {100000, 4}];
Timing[pr /@ data;]

takes 5.0 seconds. Compare this to 94 seconds for a solution involving BernoulliDistribution. Changing the test data from 100,000 lists of 4 probabilities to 1000 lists of 400 probabilities increases the time to 12.4 seconds, but the solution based on BernoulliDistribution is unable to finish! Extrapolating its performance for smaller problems suggests it would need about 2000 years.

Analysis of alternatives

The matrix-based PrV2 solution offered by @rojo is quite efficient--it works about twice as quickly as the solution offered here does--until you try passing longish arrays of probabilities as arguments. The break-even point is around 120 probabilities. After this, PrV2 scales quadratically in the argument size $n$, whereas PrV2 scales as $O(n\log(n))$. This will be a problem with any direct implementation of the formula, because it involves a sum of $n$ products of $n$ terms each: obviously $O(n^2)$ effort. The polynomial-based algorithm is superior for large lists of probabilities because (apparently) the polynomial algorithms use efficient convolutions, which tend to be $O(n\log(n))$ operations rather than $O(n^2)$.

For extremely fast calculation, you can obtain $O(n)$ asymptotics provided none of the arguments equals $0$ (or is so small as to cause numerical overflow):

pr3[p_List] := Block[{x}, (Times @@ (1 - p)) Sum[x/(1 - x), {x, p}]]

Under these slightly limited conditions, this solution will be superior in execution time to any of the others, no matter what the length of its argument:

data = RandomReal[{0, 1}, {100000, 4}];
Timing[pr3 /@ data;]

(1.7 seconds)

data = RandomReal[{0, 1}, {1, 400000}];
Timing[pr3 /@ data;]

(0.13 seconds)

  • $\begingroup$ Great stuff. You'd do well at Project Euler, if you're not already there. $\endgroup$
    – Mr.Wizard
    Mar 19, 2012 at 22:23
  • $\begingroup$ Incidentally you don't need Block in the definition of pr3. $\endgroup$
    – Mr.Wizard
    Mar 19, 2012 at 22:25
  • $\begingroup$ Mr. Wizard, I believe you, but frequently I run into trouble when I don't protect index variables in Sum, Table, or whatever, even though the docs promise that there is an implicit block already there. That's probably due to some misunderstanding of mine, but in the meantime discretion seems to be the better part of valor... $\endgroup$
    – whuber
    Mar 19, 2012 at 22:41
  • $\begingroup$ I would like to see an example of these running into trouble. $\endgroup$
    – Mr.Wizard
    Mar 19, 2012 at 23:02
  • $\begingroup$ I knew you would respond with that :-). I'll keep this site in mind the next time I run into apparent difficulties with Mathematica's scoping and I'll start a new question rather than continuing this comment thread. $\endgroup$
    – whuber
    Mar 20, 2012 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.