Every statistical claim follows the same script. Assume nothing interesting is happening (the null hypothesis H₀), collect data, and ask: if H₀ were true, how surprising would this data be? That surprise, quantified, is the p-value. If it drops below a pre-chosen threshold α (usually 0.05), you reject H₀ in favour of the alternative H₁.
| H₀ is true | H₀ is false | |
|---|---|---|
| Reject H₀ | Type I error (prob α) | Correct — power (1−β) |
| Fail to reject | Correct | Type II error (prob β) |
- State H₀ and H₁ before looking at the data, and fix α up front
- Pick the test that matches your data — see choosing the right test
- Run the test, report the p-value and the effect size with a confidence interval
- Interpret: p < α means "surprising if nothing were going on" — not "large" or "important"
pip install scipy numpy
# ────────────────────────────────────────
import numpy as np
from scipy import stats
rng = np.random.default_rng(7)
control = rng.normal(100, 15, 200)
variant = rng.normal(104, 15, 200)
t, p = stats.ttest_ind(variant, control, equal_var=False)
d = (variant.mean() - control.mean()) / np.sqrt(
(control.var() + variant.var()) / 2)
print(f"t = {t:.2f}, p = {p:.4f}, Cohen's d = {d:.2f}")
5,000 experiments with no real effect: 5.0% come out significant, exactly the false-positive rate promised. 5,000 experiments with a real effect of 0.4 standard deviations and 30 per group: only 32.3% come out significant, and 18.2% land between 0.01 and 0.05. With low power, a real effect usually looks like nothing, and when it does show, it barely clears the line.
- Significant results from low-powered studies exaggerate the effect size and can even get its sign wrong (Gelman & Carlin 2014).
- When most tested hypotheses are false, most significant findings can be false too (Ioannidis 2005).
- p < 0.05 is a convention, not a law; report the estimate and its interval.
from scipy.stats import ttest_ind rng = np.random.default_rng(18) x = rng.normal(0, 1, (5_000, 60)) # 5,000 experiments, two groups of 30, no effect y = rng.normal(0, 1, (5_000, 60)); y[:, 30:] += 0.4 # 5,000 more with a real effect of 0.4 SD null = ttest_ind(x[:, :30], x[:, 30:], axis=1).pvalue # one t-test per row real = ttest_ind(y[:, :30], y[:, 30:], axis=1).pvalue share = (round((null < 0.05).mean(), 3), round((real < 0.05).mean(), 3)) near_miss = round(((real > 0.01) & (real < 0.05)).mean(), 3)
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 — one-sample and two-sample tests from scipy import stats import numpy as np # Does this sample's mean differ from 100? sample = np.random.normal(103, 15, size=50) t_stat, p_val = stats.ttest_1samp(sample, popmean=100) print(f"t = {t_stat:.2f}, p = {p_val:.4f}") # Do two groups differ? t_stat, p_val = stats.ttest_ind(group_a, group_b) alpha = 0.05 if p_val < alpha: print("Reject H0 — difference is statistically significant") else: print("Fail to reject H0 — not enough evidence")
- R. L. Wasserstein & N. A. Lazar, “The ASA Statement on p-Values: Context, Process, and Purpose”, The American Statistician 70(2), 2016
- J. P. A. Ioannidis, “Why Most Published Research Findings Are False”, PLoS Medicine 2(8), 2005
- A. Gelman & J. Carlin, “Beyond Power Calculations: Assessing Type S (Sign) and Type M (Magnitude) Errors”, Perspectives on Psychological Science 9(6), 2014
Last reviewed October 2026 · How this site checks its content · Report a mistake
1. A test gives p = 0.03. Which statement is correct?
Show answer
B. A p-value is computed assuming the null is true, so it cannot be the probability that the null is true. It also says nothing about size: a tiny effect in a huge sample can give a tiny p-value.
2. You test 20 independent metrics at α = 0.05, and none of them is really affected. How likely is at least one “significant” result?
Show answer
A. Each test has a 95% chance of staying quiet, so all twenty stay quiet with probability 0.9520 ≈ 0.36. The other 64% of the time something crosses the line by chance — the garden of forking paths.
3. A study reports p = 0.20 for a new treatment. What can you conclude?
Show answer
C. Failing to reject is not proof of the null. With a small sample (low power) a real effect often gives p > 0.05; report the effect size and its confidence interval instead.
- Pattern EssaysThe Garden of Forking PathsTry enough paths and one of them will lead somewhere by luck alone
- Pattern EssaysThe ThresholdMany systems stay quiet for a long time, then change all at once
- LLM EngineeringEvaluation & BenchmarksMeasuring what matters — and what doesn't
- Chart PatternsDouble TopTwo peaks at the same level — the "M" formation
- Market PsychologyHindsight BiasOnce the outcome is known it feels as if it was predictable all along, and memory quietly rewrites the odds
- Risk & PortfolioPairs TradingLong/short correlated pairs to profit from spread convergence
- ML MathKL DivergenceMeasuring how different two probability distributions are
- ML MathEval MetricsHow to actually measure if your model is good
- ML MathRLHFMaking language models helpful, harmless, and honest with human feedback