8. Basic Probability
Level: Beginner You'll use this for: reasoning about A/B tests, retry logic, and every "how likely is this" question, including security alert quality.
Core definitions
- Sample space (
Ω): every possible outcome. - Event (
A): a subset of outcomes you care about. - P(A): a number from 0 to 1.
P(A) = 0never happens,P(A) = 1always happens.
Independence vs. dependence
Two events are independent if one doesn't affect the other's
probability: P(A ∩ B) = P(A) · P(B). Coin flips are independent (the coin
has no memory) — this is why "I've flipped 5 heads in a row, tails is due"
(the gambler's fallacy) is simply wrong. Each flip is still 50/50.
Worked example: retry probability
A flaky network call succeeds with probability p = 0.7 per attempt,
independently. What's the probability all 3 retries fail?
P(fail once) = 1 - p = 0.3
P(fail 3 times in a row) = 0.3³ = 0.027 (2.7%)
P(at least one success in 3 tries) = 1 - 0.027 = 0.973
p_fail = 1 - 0.7
p_all_fail = p_fail ** 3
print(1 - p_all_fail) # 0.973
This is the actual math behind "3 retries with independent failure modes gets you from 70% to 97.3% reliability" — and why retries must hit independent failure domains (different replicas/AZs) to actually compound; retrying the same overloaded server 3 times doesn't multiply independent probabilities, because the failures are correlated.
Union of events (why "or" isn't just addition)
P(A ∪ B) = P(A) + P(B) - P(A ∩ B)
You subtract the overlap so you don't double count it. Forgetting the
-P(A ∩ B) term is the single most common basic probability bug.
The three axioms everything else is built on
In 1933 Andrey Kolmogorov showed that all of probability theory follows from
three rules. Every formula in this guide that involves P(...), from Bayes to
the Poisson distribution, can be derived from these three.
1. P(A) ≥ 0 for every event A
2. P(Ω) = 1 something in the sample space happens
3. P(A ∪ B) = P(A) + P(B) when A and B can't both happen (A ∩ B = ∅)
| Symbol | Say it as | Meaning |
|---|---|---|
Ω |
"omega" | the sample space: every possible outcome |
A ∪ B |
"A union B" | A happens, or B happens, or both |
A ∩ B |
"A intersect B" | A and B both happen |
∅ |
"empty set" | an impossible event |
Example: the complement rule, P(not A) = 1 - P(A), isn't a separate
fact you memorize. A and not A can't both happen, and together they cover
Ω. So by axiom 3, P(A) + P(not A) = P(Ω), and by axiom 2 that equals 1.
The retry example above (1 - 0.027) used exactly this.
Conditional probability: updating on new information
P(A | B) = P(A ∩ B) / P(B) (defined when P(B) > 0)
| Symbol | Say it as | Meaning |
|---|---|---|
P(A | B) |
"probability of A given B" | the probability of A once you know B happened |
P(A ∩ B) |
"probability of A and B" | both happen together |
P(B) |
"probability of B" | the condition, which becomes your new "whole world" |
Read it as zooming in. Once you know B happened, every outcome outside
B is gone. B becomes the new universe, and you ask what fraction of it
also lies inside A.
Example: from logs, 2% of requests are to /checkout, and 0.5% of all
requests are /checkout requests that failed. What is the failure rate
of checkout requests?
P(fail | checkout) = P(fail ∩ checkout) / P(checkout) = 0.005 / 0.02 = 0.25 -> 25%
A global failure rate that looks fine can hide one endpoint that fails a quarter of the time. This is why SLO dashboards slice by route.
The law of total probability: divide and conquer
If B₁, B₂, …, Bₙ split the world into non-overlapping cases that cover
everything:
P(A) = Σᵢ P(A | Bᵢ) · P(Bᵢ)
| Symbol | Meaning |
|---|---|
Bᵢ |
the i-th case (e.g. "request routed to zone i") |
P(Bᵢ) |
how often case i happens (the weights must sum to 1) |
P(A | Bᵢ) |
how likely A is inside case i |
Σᵢ |
add up over every case i = 1 … n |
Example (networking): a global load balancer sends 50% of traffic to zone 1, 30% to zone 2 and 20% to zone 3. The per-zone packet-loss rates are 0.1%, 0.2% and 1%. What is the overall loss rate?
P(loss) = 0.001·0.5 + 0.002·0.3 + 0.010·0.2
= 0.0005 + 0.0006 + 0.0020
= 0.0031 -> 0.31%
Now run it backwards with Bayes (Ch. 16): given that a packet was lost, how
likely is it that it went through zone 3? 0.0020 / 0.0031 ≈ 65%. Zone 3
carries only 20% of traffic but causes 65% of the loss, so that's where to
look first. Total probability plus Bayes is the maths behind "which
component is responsible for most of the errors?"
Random variables and expected value
A random variable X is a number whose value is decided by chance, such
as the number of retries, a request's latency, or the bytes in a flow. Its
expected value is the long-run average you'd see over many repetitions:
E[X] = Σₓ x · P(X = x) (discrete: weighted sum of outcomes)
E[X] = ∫ x · f(x) dx (continuous: weighted integral, Ch. 12)
| Symbol | Say it as | Meaning |
|---|---|---|
E[X] |
"the expectation of X" | the probability-weighted average value |
x |
"little x" | one particular value X can take |
P(X = x) |
"probability X equals x" | how often that value occurs |
f(x) |
"the density of X at x" | the continuous version of P(X = x) (Ch. 14) |
Example: how many attempts does a flaky call take, on average? Each
attempt succeeds independently with probability p. The number of attempts
until the first success follows a geometric distribution, and its
expectation works out to:
E[attempts] = 1·p + 2·(1-p)·p + 3·(1-p)²·p + ... = 1/p
With p = 0.7, that's 1/0.7 ≈ 1.43 attempts per call on average, so a
retrying client puts about 43% more load on the backend than a
non-retrying one. A backend that fails more (smaller p) gets more
traffic. That feedback loop is how retry storms happen.
Networking in the wild: the ETX routing metric. In wireless mesh networks
(MIT's Roofnet, then the Linux OLSR and B.A.T.M.A.N. routing daemons), a
link's cost is its expected transmission count. If a data frame gets
through with probability d_f and its ACK comes back with probability
d_r, an attempt succeeds with probability d_f · d_r, so:
ETX = 1 / (d_f · d_r)
| Path | Calculation | Expected transmissions |
|---|---|---|
1 hop, a bad link (d_f = d_r = 0.5) |
1 / (0.5·0.5) |
4.0 |
2 hops, two good links (0.9 each way) |
2 × 1 / (0.9·0.9) |
2.47 |
Hop-count routing picks the 1-hop path because it has fewer hops. ETX routing picks the 2-hop path because, on average, it uses the air about 40% less. The difference is just expected value.
Linearity of expectation: the most useful "free lunch" in probability
E[X + Y] = E[X] + E[Y] ALWAYS, even if X and Y are dependent
E[c · X] = c · E[X] for any constant c
The surprising part is that this works without independence. That lets you break a hard count into easy indicator pieces and add up their expectations.
Example: expected hash collisions. Insert n = 1000 keys into a hash
table with m = 10,000 buckets. How many pairs of keys share a bucket, on
average? For each of the C(n,2) pairs (Ch. 15), let an indicator be 1 if
that pair collides. Each pair collides with probability 1/m. So:
E[colliding pairs] = C(n,2) · (1/m) = (1000·999/2) / 10000 = 499,500 / 10,000 ≈ 50
That's about 50 collisions with the table only 10% full. Linearity of expectation answered it in one line, with no need to work out the messy joint distribution. The same argument gives the birthday bound in Ch. 24.
AI in the wild: why dropout rescales. During training, dropout zeroes
each neuron's output h with probability 1 - q (so it keeps it with
probability q). The expected output becomes E[kept h] = q·h + (1-q)·0 = q·h.
At inference time nothing is dropped, so the next layer would suddenly see
inputs 1/q times larger than it was trained on. "Inverted dropout", the
default in PyTorch, divides by q during training. By linearity,
E[h/q · keep] = (1/q)·q·h = h, so the expected value is the same in
training and inference.
Variance of a random variable
Var(X) = E[(X - E[X])²] = E[X²] - (E[X])²
| Symbol | Meaning |
|---|---|
X - E[X] |
how far one outcome lands from the average |
(…)² |
squared, so misses in either direction count and big misses count more |
E[X²] - (E[X])² |
the shortcut form, easier to compute by hand |
Example: a single request that fails with probability p (a Bernoulli
variable, 1 = fail, 0 = success). E[X] = p, and since X² = X for 0/1
values, E[X²] = p. So Var(X) = p - p² = p(1-p). This is largest at
p = 0.5 and tiny near 0 or 1. That's why a rare-error metric (p = 0.001)
needs huge sample sizes before you can trust a change in it, which
Ch. 22 turns into a sample-size formula.
Real-life engineering ties
- SWE: retry/circuit-breaker design, error budget math (SRE), load test result interpretation.
- AI: every classifier outputs a probability; understanding calibration (does "90% confident" actually mean right 90% of the time?) starts here.
- Network: packet loss modeling, redundant path availability
(
1 - (1-p)^nfor n independent paths — Ch. 25 combines this with queueing). - Security: false positive rate of a detection rule is a probability; understanding independence vs. correlation of signals is the difference between a SIEM rule that actually reduces risk and one that just generates alert fatigue (see Bayes, Ch. 16).
More real-life examples:
- Cloud architects use independent-failure probability math directly when
deciding how many Availability Zones to span:
P(all zones down) = p1 · p2 · p3only holds if the zones truly fail independently — the same assumption checked in the common mistake below. - Circuit-breaker libraries (Netflix Hystrix, resilience4j) are built on the same "probability of success across independent retries" reasoning as the retry example above, and track a rolling failure probability to decide when to "open" the breaker.
- CAPTCHA and bot-detection systems reason about the probability that a sequence of behaviors (mouse movement, timing, request pattern) is exhibited by a human vs. a script — a compound probability judgment, not a single yes/no rule.
- Credential-stuffing attacks exploit the (very non-independent) fact that many users reuse the same password across services — attackers rely on this correlation, not on independent per-site guessing, which is exactly why password reuse defeats per-site rate-limiting defenses.
Common mistake
Assuming events are independent when they're not (e.g., "each server has a 1% chance of failing, so with 100 servers only 1 fails" ignores correlated failures — a single power/network outage can take down all 100 at once). This is the mathematical root of "the cloud availability zone problem."