The F-Test and F-Distribution › F-Test for Comparing Two Variances
Machine Learning from ScratchAll chapters The F-Test and F-Distribution › F-Test for Comparing Two VariancesOne section · Sections in this chapter4 / 10 ↓
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
The most direct application of the F-test compares variances between two independent populations.
Hypotheses and Test Statistic
Null hypothesis: (population variances are equal)
Alternative hypotheses:
- Two-sided:
- One-sided (greater):
- One-sided (less):
where and are the sample variances.
Convention: Place the larger sample variance in the numerator so that . This simplifies interpretation: if is much larger than 1, it suggests the numerator variance is larger than the denominator variance.
Degrees of freedom: (numerator), (denominator)
P-value calculation:
- One-sided (greater):
- Two-sided: Since the F-distribution is not symmetric, we compute
Worked Example: Manufacturing Process Comparison
A quality engineer wants to compare the consistency of two production lines making precision components. She randomly samples 20 components from Line A and 25 from Line B, measuring a critical dimension.
import numpy as np
from scipy import stats
# Measurements from two production lines (in microns from target)
np.random.seed(42)
line_a = np.random.normal(0, 4.5, 20) # True std = 4.5 microns
line_b = np.random.normal(0, 7.2, 25) # True std = 7.2 microns
# Step 1: Calculate sample statistics
n1, n2 = len(line_a), len(line_b)
var1 = np.var(line_a, ddof=1)
var2 = np.var(line_b, ddof=1)
std1, std2 = np.sqrt(var1), np.sqrt(var2)
# Step 2: Arrange so larger variance is in numerator
if var1 >= var2:
f_stat = var1 / var2
df1, df2 = n1 - 1, n2 - 1
larger, smaller = "A", "B"
else:
f_stat = var2 / var1
df1, df2 = n2 - 1, n1 - 1
larger, smaller = "B", "A"
# Step 3: Calculate p-value (two-sided)
p_upper = stats.f.sf(f_stat, df1, df2)
p_value_two_sided = 2 * p_upper # For two-sided test
# Step 4: Get critical values
f_crit_upper = stats.f.ppf(0.975, df1, df2)
f_crit_lower = stats.f.ppf(0.025, df1, df2)F-Test for Comparing Variances: Production Line Comparison ================================================================= Sample statistics: ----------------------------------------------------------------- Line A: n = 20, variance = 18.66, std = 4.32 microns Line B: n = 25, variance = 44.27, std = 6.65 microns F-test calculation: ----------------------------------------------------------------- Larger variance (Line B): 44.27 Smaller variance (Line A): 18.66 F-statistic: F = 44.27 / 18.66 = 2.372 Degrees of freedom: df1 = 24, df2 = 19 P-value (two-sided): 0.0588 Critical values (alpha = 0.05, two-sided): Lower: 0.426 Upper: 2.452 Decision (alpha = 0.05): ----------------------------------------------------------------- Fail to reject H_0: No significant evidence of different variances


Important Caveats
The F-test for comparing variances is highly sensitive to non-normality. If the underlying populations are not normally distributed, the F-test can give misleading results even with moderate sample sizes. The t-test is less sensitive to departures from normality.
For this reason, many statisticians prefer alternatives that are less sensitive to non-normality:
- Levene's test: Uses absolute deviations from the mean or median and is less sensitive to non-normality
- Brown-Forsythe test: A variant of Levene's test using the median
- Bartlett's test: More powerful under normality but sensitive to non-normality
When checking the equal variance assumption for a t-test:
- Visual inspection (boxplots, standard deviation ratio) is often sufficient
- If a formal test is needed, use Levene's test rather than the F-test
- When in doubt about equal variances, simply use Welch's t-test, which doesn't assume equal variances
from scipy import stats
# Comparing F-test vs Levene's test
np.random.seed(42)
group1 = np.random.normal(50, 5, 30)
group2 = np.random.normal(50, 10, 30)
# F-test
f_stat = np.var(group2, ddof=1) / np.var(group1, ddof=1)
f_pvalue = 2 * stats.f.sf(f_stat, 29, 29)
# Levene's test (more robust)
levene_stat, levene_pvalue = stats.levene(group1, group2)
print("Comparison of variance equality tests:")
print("-" * 50)
print(f"F-test: F = {f_stat:.2f}, p = {f_pvalue:.4f}")
print(f"Levene's: W = {levene_stat:.2f}, p = {levene_pvalue:.4f}")
print()
print("Both detect the variance difference, but Levene's test")
print("is preferred because it's robust to non-normality.")Comparison of variance equality tests: -------------------------------------------------- F-test: F = 4.28, p = 0.0002 Levene's: W = 14.64, p = 0.0003 Both detect the variance difference, but Levene's test is preferred because it's robust to non-normality.