Confidence Intervals and Test Assumptions › Welch's T-Test: The Safer Default
Machine Learning from ScratchAll chapters Confidence Intervals and Test Assumptions › Welch's T-Test: The Safer DefaultOne section · Sections in this chapter6 / 9 ↓
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
When comparing two independent groups, Welch's t-test should be your default choice.
The Pooled vs Welch Comparison
Pooled (Student's) t-test assumes equal variances:
Welch's t-test allows unequal variances:
The degrees of freedom for Welch's test are calculated using the Welch-Satterthwaite formula:
This formula typically gives a non-integer value for degrees of freedom.
When to Use Which
| Condition | Recommended Test | Reason |
|---|---|---|
| Variances clearly equal | Either works | Pooled slightly more powerful |
| Variances uncertain | Welch's | Allows unequal variances |
| Variances clearly unequal | Welch's | Pooled will be biased |
| Default choice | Welch's | Minimal cost if variances are equal |
import numpy as np
from scipy import stats
# Example: Comparing two treatments with different variability
np.random.seed(42)
# Treatment A: Lower mean, lower variance
treatment_a = np.random.normal(50, 5, 25)
# Treatment B: Higher mean, higher variance
treatment_b = np.random.normal(55, 12, 30)
print(
f"Treatment A: mean = {np.mean(treatment_a):.2f}, std = {np.std(treatment_a, ddof=1):.2f}, n = {len(treatment_a)}"
)
print(
f"Treatment B: mean = {np.mean(treatment_b):.2f}, std = {np.std(treatment_b, ddof=1):.2f}, n = {len(treatment_b)}"
)
print()
# Pooled t-test (assumes equal variances)
t_pooled, p_pooled = stats.ttest_ind(treatment_a, treatment_b, equal_var=True)
print(f"Pooled t-test: t = {t_pooled:.3f}, p = {p_pooled:.4f}")
# Welch's t-test (allows unequal variances)
t_welch, p_welch = stats.ttest_ind(treatment_a, treatment_b, equal_var=False)
print(f"Welch's t-test: t = {t_welch:.3f}, p = {p_welch:.4f}")Treatment A: mean = 49.18, std = 4.78, n = 25 Treatment B: mean = 52.49, std = 10.79, n = 30 Pooled t-test: t = -1.418, p = 0.1621 Welch's t-test: t = -1.509, p = 0.1389
In this example, Treatment B has more than twice the variance of Treatment A. The Welch's t-test correctly accounts for this, while the pooled test uses an inappropriate compromise variance estimate.