Chapter 78 · Solutions
ANOVA — Worked Solutions ✅
Five challenges, each verified in code.
⚙️ Setup¶
In [1]:
import numpy as np, pandas as pd
from scipy import stats
import statsmodels.api as sm
from statsmodels.formula.api import ols
from statsmodels.stats.multicomp import pairwise_tukeyhsd
BASE="https://raw.githubusercontent.com/johnfisher-ai/Statistics-Data-Science-AI-Visual-Book/main/data/"
rng=np.random.default_rng(780)
CHALLENGE 1
One-way ANOVA
Three groups N(20,5,n=30), N(22,5,n=30), N(26,5,n=30). Run a one-way ANOVA.
In [2]:
g=[rng.normal(m,5,30) for m in (20,22,26)]; F,p=stats.f_oneway(*g)
print(f"F={F:.2f}, p={p:.2e}")
F=7.66, p=8.63e-04
CHALLENGE 2
Effect size eta-squared
For those groups compute eta^2 = SS_between / SS_total.
In [3]:
allv=np.concatenate(g); grand=allv.mean()
ssb=sum(len(x)*(x.mean()-grand)**2 for x in g); sst=((allv-grand)**2).sum()
print(f"eta^2 = {ssb/sst:.3f}")
eta^2 = 0.150
CHALLENGE 3
ANOVA equals the t-test for 2 groups
Show that for exactly 2 groups, F = t^2.
In [4]:
a=rng.normal(10,3,40); b=rng.normal(12,3,40)
t=stats.ttest_ind(a,b,equal_var=True).statistic; F=stats.f_oneway(a,b).statistic
print(f"t^2={t**2:.3f}, F={F:.3f} -> equal")
t^2=1.641, F=1.641 -> equal
CHALLENGE 4
Tukey HSD with statsmodels
For the three groups in #1, find which pairs differ (alpha=0.05) using pairwise_tukeyhsd.
In [5]:
vals=np.concatenate(g); labels=sum([[n]*30 for n in ["G1","G2","G3"]], [])
print(pairwise_tukeyhsd(vals, labels).summary())
Multiple Comparison of Means - Tukey HSD, FWER=0.05
===================================================
group1 group2 meandiff p-adj lower upper reject
---------------------------------------------------
G1 G2 1.1616 0.6725 -2.0933 4.4165 False
G1 G3 5.097 0.001 1.8421 8.3519 True
G2 G3 3.9355 0.0136 0.6806 7.1904 True
---------------------------------------------------
CHALLENGE 5
Real data: carriers
Load anova--carrier_delivery.xlsx; run the ANOVA (ols + anova_lm) and Tukey across carriers.
In [6]:
try: d = pd.read_excel("../../data/anova--carrier_delivery.xlsx", sheet_name="Shipments")
except FileNotFoundError: d = pd.read_excel(BASE+"anova--carrier_delivery.xlsx", sheet_name="Shipments")
print(sm.stats.anova_lm(ols("delivery_hours ~ C(carrier)", data=d).fit(), typ=2).round(3))
print(pairwise_tukeyhsd(d.delivery_hours, d.carrier).summary())
sum_sq df F PR(>F) C(carrier) 2173.764 2.0 22.914 0.0 Residual 11241.803 237.0 NaN NaN
Multiple Comparison of Means - Tukey HSD, FWER=0.05 =========================================================== group1 group2 meandiff p-adj lower upper reject ----------------------------------------------------------- FastFreight GroundLink 5.4793 0.0 2.9109 8.0476 True FastFreight RegionalCo 7.0106 0.0 4.4423 9.579 True GroundLink RegionalCo 1.5314 0.3393 -1.037 4.0997 False -----------------------------------------------------------
Statistics, Data Science and AI: A Visual Handbook · © 2026 John Fisher