Chapter 90 · Solutions
Correlation — 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
BASE="https://raw.githubusercontent.com/johnfisher-ai/Statistics-Data-Science-AI-Visual-Book/main/data/"
rng=np.random.default_rng(900)
CHALLENGE 1
Pearson r and r-squared
For a pair with rho=0.6, compute Pearson r and report r^2 as a percentage.
In [2]:
x=rng.normal(0,1,400); y=0.6*x+np.sqrt(1-0.36)*rng.normal(0,1,400)
r,_=stats.pearsonr(x,y); print(f"r={r:.2f}, r^2={r**2:.0%}")
r=0.63, r^2=40%
CHALLENGE 2
Spearman beats Pearson on a curve
For y=x^3, show Spearman rho is near 1 but Pearson r is lower.
In [3]:
x=np.sort(rng.uniform(-3,3,200)); y=x**3+rng.normal(0,1,200)
print(f"Pearson={stats.pearsonr(x,y)[0]:.2f}, Spearman={stats.spearmanr(x,y)[0]:.2f}")
Pearson=0.91, Spearman=0.95
CHALLENGE 3
Outlier robustness
Add one outlier to a clean linear pair; compare Pearson and Spearman.
In [4]:
a=rng.normal(0,1,100); b=a+rng.normal(0,0.3,100); a[0],b[0]=8,-8
print(f"Pearson={stats.pearsonr(a,b)[0]:+.2f}, Spearman={stats.spearmanr(a,b)[0]:+.2f}")
Pearson=+0.20, Spearman=+0.89
CHALLENGE 4
Partial correlation
x and y both driven by z. Show the partial correlation controlling for z collapses.
In [5]:
z=rng.normal(0,1,300); x=z+rng.normal(0,0.5,300); y=z+rng.normal(0,0.5,300)
def resid(v,w): return sm.OLS(v,sm.add_constant(w)).fit().resid
print(f"raw={stats.pearsonr(x,y)[0]:.2f}, partial(|z)={stats.pearsonr(resid(x,z),resid(y,z))[0]:.2f}")
raw=0.81, partial(|z)=0.07
CHALLENGE 5
Real data: correlation matrix
Load correlation-coefficients--fitness.xlsx and print the correlations of every variable with vo2max, sorted.
In [6]:
try: d = pd.read_excel("../../data/correlation-coefficients--fitness.xlsx", sheet_name="Members")
except FileNotFoundError: d = pd.read_excel(BASE+"correlation-coefficients--fitness.xlsx", sheet_name="Members")
cols=["age","height_cm","weight_kg","body_fat_pct","weekly_exercise_hrs","resting_hr","vo2max"]
print(d[cols].corr()["vo2max"].drop("vo2max").sort_values().round(2))
body_fat_pct -0.85 resting_hr -0.77 age -0.56 weight_kg -0.47 height_cm -0.01 weekly_exercise_hrs 0.78 Name: vo2max, dtype: float64
Statistics, Data Science and AI: A Visual Handbook · © 2026 John Fisher