Chapter 80 · Solutions
Nonparametric — Worked Solutions ✅
Five challenges, each verified in code.
⚙️ Setup¶
In [1]:
import numpy as np, pandas as pd
from scipy import stats
BASE="https://raw.githubusercontent.com/johnfisher-ai/Statistics-Data-Science-AI-Visual-Book/main/data/"
rng=np.random.default_rng(800)
CHALLENGE 1
Mann-Whitney U
Compare lognormal(1.0,0.6,n=50) and lognormal(0.6,0.6,n=50) with the rank-sum test.
In [2]:
a=rng.lognormal(1.0,0.6,50); b=rng.lognormal(0.6,0.6,50)
u,p=stats.mannwhitneyu(a,b,alternative="two-sided"); print(f"U={u:.1f}, p={p:.4f}")
U=1772.0, p=0.0003
CHALLENGE 2
Outlier robustness
Add one outlier of 500 to a clean N(50,8,40) sample; compare how the t-test p and Mann-Whitney p vs N(52,8,40) change.
In [3]:
clean=rng.normal(50,8,40); other=rng.normal(52,8,40); dirty=clean.copy(); dirty[0]=500
print(f"t-test (dirty) p={stats.ttest_ind(dirty,other).pvalue:.3f}")
print(f"Mann-Whitney (dirty) p={stats.mannwhitneyu(dirty,other).pvalue:.3f} (ranks ignore the outlier\u2019s size)")
t-test (dirty) p=0.522 Mann-Whitney (dirty) p=0.071 (ranks ignore the outlier’s size)
CHALLENGE 3
Kruskal-Wallis
Compare three skewed groups lognormal at mu=1.0,1.2,1.5 (n=40 each).
In [4]:
g=[rng.lognormal(m,0.5,40) for m in (1.0,1.2,1.5)]; H,p=stats.kruskal(*g)
print(f"H={H:.2f}, p={p:.4f}")
H=24.73, p=0.0000
CHALLENGE 4
Wilcoxon signed-rank
Paired: before=lognormal(1.2,0.4,30), after=before*uniform(0.7,0.95). Test the paired drop.
In [5]:
before=rng.lognormal(1.2,0.4,30); after=before*rng.uniform(0.7,0.95,30)
w,p=stats.wilcoxon(after,before); print(f"W={w:.1f}, p={p:.4f}")
W=0.0, p=0.0000
CHALLENGE 5
Real data: ticket times
Load nonparametric-tests--ticket_times.xlsx; run Mann-Whitney (Alpha vs Bravo) and Kruskal-Wallis (by priority).
In [6]:
try: d = pd.read_excel("../../data/nonparametric-tests--ticket_times.xlsx", sheet_name="Tickets")
except FileNotFoundError: d = pd.read_excel(BASE+"nonparametric-tests--ticket_times.xlsx", sheet_name="Tickets")
A=d[d.team=="Alpha"].resolution_hours; B=d[d.team=="Bravo"].resolution_hours
print(f"Mann-Whitney p={stats.mannwhitneyu(A,B).pvalue:.4f}")
g=[x.resolution_hours.values for _,x in d.groupby("priority")]
print(f"Kruskal-Wallis p={stats.kruskal(*g).pvalue:.2e}")
Mann-Whitney p=0.0469 Kruskal-Wallis p=3.76e-07
Statistics, Data Science and AI: A Visual Handbook · © 2026 John Fisher