Sample Size, Minimum Detectable Effect, and Power › Minimum Detectable Effect (MDE)
Machine Learning from ScratchAll chapters Sample Size, Minimum Detectable Effect, and Power › Minimum Detectable Effect (MDE)One section · Sections in this chapter5 / 12 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Sometimes you have a fixed sample size (due to budget, time, or available participants) and need to know: What's the smallest effect this study can reliably detect?
The minimum detectable effect (MDE) answers this question. It's the effect size threshold below which your study has inadequate power.
Deriving the MDE Formula
Rearranging the sample size formula to solve for effect size:
For a two-sample test:
def minimum_detectable_effect(
n, alpha=0.05, power=0.80, test_type="one_sample"
):
"""
Calculate the minimum detectable effect size (Cohen's d).
Parameters:
-----------
n : int
Sample size (total for one-sample, per group for two-sample)
alpha : float
Significance level (two-tailed)
power : float
Desired power
test_type : str
'one_sample' or 'two_sample'
Returns:
--------
float : Minimum detectable Cohen's d
"""
z_alpha = stats.norm.ppf(1 - alpha / 2)
z_beta = stats.norm.ppf(power)
if test_type == "two_sample":
mde = (z_alpha + z_beta) / np.sqrt(n / 2)
else:
mde = (z_alpha + z_beta) / np.sqrt(n)
return mde
# Example: What can we detect with n = 50?
print("Minimum Detectable Effect (Cohen's d) with 80% power, α = 0.05:\n")
for n in [20, 50, 100, 200, 500]:
mde_one = minimum_detectable_effect(n, test_type="one_sample")
mde_two = minimum_detectable_effect(n, test_type="two_sample")
print(
f"n = {n:3d}: One-sample d = {mde_one:.3f}, Two-sample d = {mde_two:.3f}"
)Minimum Detectable Effect (Cohen's d) with 80% power, α = 0.05: n = 20: One-sample d = 0.626, Two-sample d = 0.886 n = 50: One-sample d = 0.396, Two-sample d = 0.560 n = 100: One-sample d = 0.280, Two-sample d = 0.396 n = 200: One-sample d = 0.198, Two-sample d = 0.280 n = 500: One-sample d = 0.125, Two-sample d = 0.177

MDE in Practice: A/B Testing
MDE is particularly important for A/B testing in tech companies. Before running an experiment, you need to know:
- What's the smallest improvement worth detecting?
- How much traffic/time do we need to detect it?
def ab_test_mde_proportions(n_per_group, baseline_rate, alpha=0.05, power=0.80):
"""
Calculate MDE for an A/B test on proportions (e.g., conversion rate).
Parameters:
-----------
n_per_group : int
Sample size per group
baseline_rate : float
Expected conversion rate in control group
alpha : float
Significance level
power : float
Desired power
Returns:
--------
tuple : (absolute MDE, relative MDE as percentage lift)
"""
z_alpha = stats.norm.ppf(1 - alpha / 2)
z_beta = stats.norm.ppf(power)
# Standard error under null (pooled)
se_null = np.sqrt(2 * baseline_rate * (1 - baseline_rate) / n_per_group)
# Standard error under alternative (approximate)
se_alt = se_null # Approximation for small effects
# MDE (absolute)
mde_abs = (z_alpha + z_beta) * se_null
# Relative lift
mde_relative = mde_abs / baseline_rate * 100
return mde_abs, mde_relative
# Example: E-commerce A/B test
baseline = 0.03 # 3% conversion rate
print(f"A/B Test MDE Analysis (baseline rate = {baseline * 100}%)\n")
print(f"{'n per group':<15} {'MDE (absolute)':<18} {'MDE (% lift)':<15}")
print("-" * 48)
for n in [1000, 5000, 10000, 50000, 100000]:
mde_abs, mde_rel = ab_test_mde_proportions(n, baseline)
print(f"{n:<15,} {mde_abs:<18.4f} {mde_rel:<15.1f}%")A/B Test MDE Analysis (baseline rate = 3.0%) n per group MDE (absolute) MDE (% lift) ------------------------------------------------ 1,000 0.0214 71.2 % 5,000 0.0096 31.9 % 10,000 0.0068 22.5 % 50,000 0.0030 10.1 % 100,000 0.0021 7.1 %
This analysis reveals an important truth: detecting small improvements in conversion rates requires very large samples. A 10% relative lift on a 3% baseline means detecting a 0.3 percentage point improvement, which requires roughly 35,000 users per group.