What Conditional Probability Means
The Question Conditional Probability Answers
Ordinary probability asks: what is the chance of A? Conditional probability asks a sharper question: what is the chance of A given that we already know B happened? That single qualifier — given B — changes the sample space. You are no longer reasoning about everyone. You are reasoning only about the subset where B is true.
Formally, the conditional probability of A given B is:
P(A|B) = P(A and B) / P(B), provided P(B) > 0
Read this formula slowly. The numerator is the probability that both events occur. The denominator rescales everything to the world where B is certain. The result is the fraction of B's outcomes that are also A's outcomes.
A Concrete Example: Conversion Given Traffic Source
Suppose your site receives 10,000 visitors in a week. 2,000 come from paid search, and 8,000 come from organic. Overall, 300 visitors convert. Of the paid search visitors, 150 convert.
- P(convert) = 300 / 10,000 = 0.03 (the base conversion rate)
- P(convert | paid search) = 150 / 2,000 = 0.075
- P(convert | organic) = 150 / 8,000 = 0.01875
The base rate hides a 4x difference between channels. Conditional probability reveals it. This is why analysts who only report averages make poor decisions: the average blends subpopulations whose behavior differs materially.
Why the Denominator Is the Whole Point
The denominator is not a formality. It is the mechanism that restricts attention to the relevant subpopulation. When you compute P(convert | paid search), you discard the 8,000 organic visitors entirely. They are irrelevant to the question. Every conditional probability question has an implicit filter, and the denominator is that filter expressed as a probability.
A useful habit: before computing any conditional probability, say out loud what the denominator represents. If you cannot name the subpopulation, you have not understood the question.
Computing Conditional Probability from a Contingency Table
In practice, you rarely have probabilities handed to you. You have rows of event data. The workflow is:
- Filter the data to the condition (the denominator).
- Within that filter, count how many also satisfy the target event (the numerator).
- Divide.
import pandas as pd
df = pd.read_csv('sessions.csv') # columns: session_id, channel, converted
paid = df[df['channel'] == 'paid_search']
paid_conversion = paid['converted'].mean()
print(f'P(convert | paid search) = {paid_conversion:.4f}')
organic = df[df['channel'] == 'organic']
organic_conversion = organic['converted'].mean()
print(f'P(convert | organic) = {organic_conversion:.4f}')
The .mean() on a boolean column is the fraction of True values — exactly the conditional probability you need. This pattern (filter, then aggregate) is the workhorse of conditional analysis in pandas.
The Intuition Behind the Formula
Why divide by P(B) instead of just counting? Because probabilities must sum to 1 over the restricted sample space. If you condition on B, then B becomes your new universe, and all probabilities within that universe must be relative to it. Dividing by P(B) performs that renormalization. Without it, you would be mixing two different sample spaces in a single number, which produces nonsense.
Think of it this way: P(A and B) tells you how much of the whole universe is both A and B. P(A|B) tells you how much of B's universe is also A. The division converts between those two perspectives.
Independence: When Conditioning Changes Nothing
The Definition
Two events A and B are independent if knowing that B occurred does not change the probability of A:
P(A|B) = P(A)
Equivalently, A and B are independent if:
P(A and B) = P(A) * P(B)
The second form is often easier to check with data. If the joint probability equals the product of the marginals, the events are independent. If it does not, they are dependent — and the direction and magnitude of the dependence is exactly what conditional probability measures.
Why Independence Matters in Product Analytics
Independence is the assumption behind many naive analyses. When it holds, you can reason about metrics separately and multiply probabilities freely. When it fails, those analyses produce confidently wrong numbers.
Consider a funnel: signup, activation, first purchase. Suppose:
- P(signup) = 0.10
- P(activation | signup) = 0.40
- P(first purchase | activation) = 0.25
If activation and purchase were independent of the earlier steps, you could compute the overall conversion as 0.10 * 0.40 * 0.25 = 0.01. But they are not independent — each step is conditional on the previous one. The correct computation chains the conditionals:
P(signup and activation and purchase) = P(signup) * P(activation | signup) * P(purchase | activation)
This is the chain rule of probability, and it is the correct way to model a sequential funnel. Treating the steps as independent would give you a number that has no relationship to reality.
Testing for Independence with Data
You can test independence empirically by comparing the conditional probability to the marginal:
import pandas as pd
df = pd.read_csv('users.csv') # columns: user_id, clicked_email, purchased
p_purchase = df['purchased'].mean()
clicked = df[df['clicked_email'] == True]
p_purchase_given_click = clicked['purchased'].mean()
print(f'P(purchase) = {p_purchase:.4f}')
print(f'P(purchase | clicked) = {p_purchase_given_click:.4f}')
if abs(p_purchase_given_click - p_purchase) < 0.01:
print('Approximately independent')
else:
print('Dependent — clicking changes purchase probability')
A difference of a few percentage points may be noise. Use a statistical test (chi-square for categorical variables) before declaring dependence, especially with small samples.
Common Independence Traps
Trap 1: Assuming independence because events seem unrelated. Email clicks and purchases seem like separate behaviors. They are not — clicking signals intent, which raises purchase probability.
Trap 2: Assuming dependence because events co-occur. Two events can co-occur frequently and still be independent. Co-occurrence is about counts; independence is about whether one event's probability changes given the other.
Trap 3: Confusing mutual exclusivity with independence. Mutually exclusive events (A and B cannot both happen) are maximally dependent: if A happens, B cannot. P(A|B) = 0, which is almost never equal to P(A). Independence and mutual exclusivity are opposites, not synonyms.
The Multiplication Rule for Independent Events
When events are independent, the joint probability is the product of the marginals. This is what makes independent events analytically tractable. If two ad campaigns reach disjoint audiences, the probability that a user sees both is the product of the individual reach probabilities. If the audiences overlap, you need the conditional probability instead, and the product rule overestimates the joint probability.
The practical rule: verify independence before multiplying. If you cannot verify it, estimate the joint probability directly from data rather than assuming it.
Conditional Thinking in Funnel Analysis
Funnels Are Chains of Conditional Probabilities
A funnel is a sequence of steps where each step depends on completing the previous one. The overall conversion rate is the product of the conditional probabilities at each stage:
P(complete funnel) = P(step 1) * P(step 2 | step 1) * P(step 3 | step 2) * ...
This is the chain rule applied to a sequence. Each term is a conditional probability: the probability of completing this step given that you completed the previous one. The product gives the probability of completing the entire funnel.
Why Per-Step Rates Matter More Than the Overall Rate
Suppose your funnel has three steps with these conditional probabilities:
- Step 1 (landing to signup): 0.30
- Step 2 (signup to activation): 0.50
- Step 3 (activation to purchase): 0.20
Overall conversion: 0.30 * 0.50 * 0.20 = 0.03, or 3%.
Now suppose you improve step 2 from 0.50 to 0.60. The new overall rate is 0.30 * 0.60 * 0.20 = 0.036. That is a 20% relative improvement in overall conversion from a 10-percentage-point improvement in one step.
But if you improve step 1 from 0.30 to 0.40, the new overall rate is 0.40 * 0.50 * 0.20 = 0.04. That is a 33% relative improvement. The same 10-point gain produces a larger overall effect at the top of the funnel because it feeds more users into every subsequent step.
This is why funnel analysis focuses on per-step conditional rates. The overall rate is a derived metric that compresses all the information into a single number. The per-step rates tell you where the problem is.
Computing Funnel Drop-Off in Python
import pandas as pd
df = pd.read_csv('funnel_events.csv') # columns: user_id, step, completed
step_order = ['landing', 'signup', 'activation', 'purchase']
counts = df.groupby('step')['user_id'].nunique().reindex(step_order)
conditional_rates = {}
for i in range(1, len(step_order)):
prev, curr = step_order[i-1], step_order[i]
conditional_rates[f'{prev} -> {curr}'] = counts[curr] / counts[prev]
overall = counts['purchase'] / counts['landing']
print('Conditional rates:', conditional_rates)
print(f'Overall conversion: {overall:.4f}')
The loop computes each conditional probability as the ratio of consecutive step counts. The overall conversion is the product of these ratios — verify this yourself to see the chain rule in action.
Retention as a Conditional Probability
Retention is conditional probability applied over time. Day-7 retention is:
P(active on day 7 | active on day 0)
The denominator is users who were active on day 0. The numerator is those same users who are also active on day 7. You are asking: of the users we acquired, what fraction came back?
Cohort analysis is conditional probability organized by acquisition period. Each cohort has its own retention curve, and comparing curves across cohorts tells you whether product changes are improving retention or whether you are simply acquiring different mixes of users.
import pandas as pd
df = pd.read_csv('user_activity.csv') # columns: user_id, cohort_week, active_date
df['days_since_signup'] = (pd.to_datetime(df['active_date']) - pd.to_datetime(df['cohort_week'])).dt.days
cohort_sizes = df.groupby('cohort_week')['user_id'].nunique()
d7 = df[df['days_since_signup'] == 7].groupby('cohort_week')['user_id'].nunique()
d7_retention = d7 / cohort_sizes
print(d7_retention)
The key insight: retention is always relative to a cohort. Without the cohort denominator, you cannot compute retention at all. The cohort is the condition.
The Base Rate Fallacy
What the Base Rate Fallacy Is
The base rate fallacy is the error of ignoring the prior probability of an event when evaluating evidence about it. You focus on how strongly the evidence points to a conclusion and forget how rare the conclusion was to begin with.
Formally, it is the mistake of confusing P(evidence | hypothesis) with P(hypothesis | evidence). These are not the same. The first is the likelihood of the evidence given the hypothesis. The second is the probability of the hypothesis given the evidence — which is what you actually want to know.
A Product Analytics Example
Suppose 2% of users are "high-value" (they will spend over $500 in their lifetime). You build a model that predicts high-value users with 90% precision: when it predicts high-value, it is right 90% of the time. The model flags a user as high-value. What is the probability the user is actually high-value?
If you said 90%, you committed the base rate fallacy. The 90% is P(predicted high-value | actually high-value) — the model's precision on the positive class. But you want P(actually high-value | predicted high-value), which depends on the base rate.
Using Bayes' theorem (covered in detail in the next topic):
P(high-value | predicted) = P(predicted | high-value) * P(high-value) / P(predicted)
With a 2% base rate and a model that flags 10% of users:
P(predicted) = P(predicted | high-value) * P(high-value) + P(predicted | not high-value) * P(not high-value)
= 0.90 * 0.02 + 0.10 * 0.98
= 0.018 + 0.098 = 0.116
P(high-value | predicted) = 0.90 * 0.02 / 0.116 = 0.155
The true probability is 15.5%, not 90%. The low base rate dominates. Even a precise model produces mostly false positives when the condition is rare.
Why This Matters for Alerting and Monitoring
Anomaly detection systems face the same problem. Suppose your monitoring system flags metric anomalies with 95% precision. If true anomalies occur 1% of the time, then most flags are false positives:
P(anomaly | flag) = 0.95 * 0.01 / (0.95 * 0.01 + 0.05 * 0.99) = 0.16
Only 16% of alerts are real. This is why alert fatigue is not a UX problem — it is a probability problem. The fix is not to make the detector more sensitive; it is to either raise the threshold (trading recall for precision) or to incorporate the base rate into the alerting logic.
How to Avoid the Fallacy
Always identify the base rate first. Before evaluating any evidence, ask: how common is this condition in the population?
Use natural frequencies instead of probabilities. Instead of "2% of users," think "20 out of every 1,000 users." Natural frequencies make the base rate concrete and harder to ignore.
Apply Bayes' theorem explicitly. Do not rely on intuition. The formula forces you to account for the base rate.
Be skeptical of high precision on rare conditions. If a condition is rare, even a precise test produces mostly false positives. This is not a flaw in the test; it is a consequence of the base rate.
The Prosecutor's Fallacy in A/B Testing
A related error appears in A/B testing. Suppose variant B converts 5.1% and variant A converts 5.0%. A team member says "B is better 95% of the time." That statement confuses P(data | B is better) with P(B is better | data). The first is a property of the test design. The second requires a prior belief about how often B is actually better, combined with the observed data. Without the prior, the 95% confidence statement does not answer the decision question.
The practical takeaway: always pair any conditional probability with its base rate. The conditional tells you about the relationship between events. The base rate tells you how much that relationship matters in absolute terms.
Practice Problems
A website has 50,000 sessions: 20,000 from organic, 15,000 from paid, and 15,000 from social. Overall, 1,500 sessions convert. Of the organic sessions, 400 convert. Of the paid sessions, 600 convert. Compute P(convert | organic), P(convert | paid), and P(convert | social). Which channel has the highest conditional conversion rate?
Solution
P(convert | organic) = 400 / 20000 = 0.020
P(convert | paid) = 600 / 15000 = 0.040
P(convert | social) = (1500 - 400 - 600) / 15000 = 500 / 15000 = 0.033
Paid has the highest conditional conversion rate at 4.0%. A signup funnel has 10,000 visitors. 3,000 reach the signup page, 1,500 complete signup, 600 activate their account, and 150 make a first purchase. Compute the conditional probability of each step given the previous step, and the overall conversion rate.
Solution
P(signup page | visitor) = 3000/10000 = 0.30
P(complete signup | signup page) = 1500/3000 = 0.50
P(activate | complete signup) = 600/1500 = 0.40
P(purchase | activate) = 150/600 = 0.25
Overall = 0.30 * 0.50 * 0.40 * 0.25 = 0.015 (1.5%) In a dataset of 10,000 users, 3,000 clicked a promotional email and 2,000 made a purchase. 800 users both clicked and purchased. Are clicking and purchasing independent? Show your reasoning.
Solution
P(click) = 3000/10000 = 0.30
P(purchase) = 2000/10000 = 0.20
P(click and purchase) = 800/10000 = 0.08
If independent: P(click) * P(purchase) = 0.30 * 0.20 = 0.06
Since 0.08 != 0.06, the events are dependent. Clicking increases purchase probability: P(purchase | click) = 800/3000 = 0.267, which is higher than the marginal P(purchase) = 0.20. Quiz
1. What does P(A|B) represent?
2. Two events A and B are independent if:
3. The base rate fallacy is:
Flashcards
Question
What is the formula for conditional probability?
Click to reveal answer
Answer
P(A|B) = P(A and B) / P(B), provided P(B) > 0. The denominator restricts the sample space to outcomes where B is true.
Question
How do you test whether two events are independent?
Click to reveal answer
Answer
Check if P(A and B) = P(A) * P(B). If the joint probability equals the product of the marginals, the events are independent. Equivalently, check if P(A|B) = P(A).
Question
Why does the base rate matter when interpreting a positive test result?
Click to reveal answer
Answer
When a condition is rare, even a precise test produces mostly false positives. P(condition | positive) depends on the base rate P(condition), not just the test's precision.
Question
How is a funnel conversion rate decomposed using conditional probability?
Click to reveal answer
Answer
Overall conversion = P(step 1) * P(step 2 | step 1) * P(step 3 | step 2) * ... Each term is the conditional probability of completing a step given the previous step was completed.
Revision Notes
Key Takeaways
- 1. Conditional probability restricts the sample space to the condition
- 2. Independence means conditioning does not change the probability
- 3. Funnels are chains of conditional probabilities multiplied together
- 4. The base rate fallacy ignores prior probability when evaluating evidence
- 5. Per-step conditional rates reveal where funnels leak; overall rates hide it
Interview Tips
- • When asked about conversion differences, compute conditional rates per segment before comparing
- • Be ready to explain why a precise anomaly detector still produces mostly false positives on rare events
- • If asked about funnel improvement, identify the step with the lowest conditional probability and quantify the overall impact of improving it
Cheat Sheet
Cheat Sheet: Conditional Probability
Core Formula
- P(A|B) = P(A and B) / P(B)
Independence
- P(A|B) = P(A) ⟺ P(A and B) = P(A) * P(B)
- Verify with data: compare joint to product of marginals
Funnel Analysis
- Overall = product of per-step conditional probabilities
- Per-step rate = count at step / count at previous step
- Largest drop-off = priority for improvement
Base Rate Fallacy
- P(evidence | hypothesis) ≠ P(hypothesis | evidence)
- Rare conditions → mostly false positives even with precise tests
- Always pair conditional probabilities with base rates
Pandas Pattern
- Filter to condition, then aggregate: df[condition][target].mean()