30 — Statistical Foundations

Correlation, Causation & Simpson's Paradox#

StatisticsStatistical 1 min read
◆ The PatternConfounders, spurious correlations, and trends that reverse when you split the data

Correlation measures whether two variables move together — nothing more. A strong r can come from X causing Y, Y causing X, a hidden confounder Z driving both, selection effects, or plain chance. Simpson's paradox is the most dramatic failure: a trend that holds in every subgroup can reverse when the groups are pooled.

r = cov(X, Y) / (σX · σY) ∈ [−1, 1]
Pearson r = linear co-movement only. r = 0 does not mean independent; r = 0.9 does not mean causal.
// Interactive Simpson's paradox — increase the confounder, watch the pooled trend flip against the groups
Confounder strength0.70
Pooled r—
Within-group r—
Why X and Y correlateExampleAntidote
X causes YPrice cut → more salesRandomized experiment confirms it
Y causes XMore police ↔ more crime (reverse)Temporal ordering, natural experiments
Confounder ZIce cream ↔ drownings (summer)Stratify or control for Z
Selection biasOnly survivors measuredAudit how the sample was formed
ChanceAny two trending seriesOut-of-sample checks, corrections
Which number is right? Neither, automatically. If severity drives both dose and recovery, the within-group trend is the honest one. The answer depends on the causal structure — what drives what — not on the arithmetic.
Pattern bridge: Feature correlation shows the same trap inside models, and survivorship bias is selection-driven correlation in backtests. The only clean escape is randomization — the logic behind A/B testing.
How to use this in practice
  1. Before trusting any correlation, list plausible confounders — time, size, cohort, seasonality are the usual suspects
  2. Recompute the relationship within each stratum of the confounder (groupby is enough)
  3. If pooled and stratified trends disagree, resolve it with causal knowledge, not with more data
  4. For decisions that matter, push for a randomized test — it severs every confounder at once
Common pitfall — controlling for everything: conditioning on a variable that sits between cause and effect (a mediator), or on a common effect (a collider), creates bias instead of removing it. Adding every column to a regression is not caution — think about the causal graph first.
When to use this
✓ Use when: Any observational comparison — dashboards, cohort metrics, "users who do X retain better" claims, feature-importance readings you are tempted to act on.
✗ Skip when: The data comes from a properly randomized experiment — randomization already balances confounders (but check the randomization actually held).
Try it on real data
The classic case: UC Berkeley admissions (Simpson's paradox) Palmer Penguins (pooled vs per-species correlations flip sign)
In the penguins data, bill length vs bill depth correlates negatively pooled — and positively within every species. A Simpson's paradox you can groupby in one line.
Quick start — copy to notebook
pip install pandas seaborn
# ────────────────────────────────────────
import seaborn as sns

df = sns.load_dataset('penguins').dropna()

pooled = df['bill_length_mm'].corr(df['bill_depth_mm'])
within = df.groupby('species').apply(
    lambda g: g['bill_length_mm'].corr(g['bill_depth_mm']))

print(f"pooled r = {pooled:.2f}")   # negative!
print(within.round(2))              # all positive
Worked example

Talent and looks are independent in 20,000 people (r = −0.002). Look only at the 1,568 who are noticed because their sum is high, and the correlation is −0.75: among the famous, the talented seem plain and the beautiful seem untalented. Selecting on an outcome creates correlations that do not exist — Berkson’s paradox, or collider bias.

Where it misleads
  • Collider bias is created by conditioning — through selection, filtering or “controlling for” a variable that both causes affect.
  • Datasets of applicants, patients or customers are already selected; correlations inside them can be artefacts.
  • Adding more variables to a regression does not fix this; adding the wrong one causes it.
In code
rng = np.random.default_rng(21)
talent, looks = rng.normal(size=(2, 20_000))         # independent in the population
famous = talent + looks > 2                          # only the top on the sum get noticed
r_all = np.corrcoef(talent, looks)[0, 1]
r_famous = np.corrcoef(talent[famous], looks[famous])[0, 1]
Python, in your browser — edit the code and run it again

Assumes import numpy as np and import pandas as pd (and SciPy where imported). Each snippet simulates or makes up its own data, as the comments say.

The same idea with a library
# Python — Simpson's paradox in three lines of groupby
import pandas as pd

# Pooled correlation says one thing…
print(df[['dose', 'recovery']].corr().iloc[0, 1])

# …every subgroup says the opposite
print(df.groupby('severity')
        .apply(lambda g: g['dose'].corr(g['recovery'])))

# Always check candidate confounders before trusting a trend
pd.crosstab(df['severity'], df['treatment'], normalize='index')
Sources
  • J. Berkson, “Limitations of the Application of Fourfold Table Analysis to Hospital Data”, Biometrics Bulletin 2(3), 1946
  • Causal Inference in Statistics: A Primer, J. Pearl, M. Glymour & N. P. Jewell, Wiley, 2016
  • F. Elwert & C. Winship, “Endogenous Selection Bias: The Problem of Conditioning on a Collider Variable”, Annual Review of Sociology 40, 2014

Last reviewed October 2026 · How this site checks its content · Report a mistake

Check yourself

1. Across a year, ice-cream sales and drownings rise and fall together. What is the best explanation?

Show answer

B. Warm days bring both ice cream and swimming. The correlation is real and even useful for forecasting; it just runs through a confounder rather than from one to the other.

2. Two variables have a correlation of r = 0. What does that tell you?

Show answer

C. Pearson’s r only measures straight-line association. If x is symmetric around zero, y = x² is completely determined by x and still has r ≈ 0. Plot the data.

3. Which evidence best supports a causal claim?

Show answer

A. Randomization makes the groups alike in everything except the treatment, confounders included. More observational data makes a biased estimate more precise, not less biased.

Linked from 2
← Previous
Central Limit Theorem & Sampling
Open in the full reader, with the topic sidebar