What You'll Build
In this first stage of the capstone you will build the descriptive and distributional analysis of the clinical-trial dataset, producing a thorough summary of every variable and characterising the distributions that govern them. You will compute central tendency, spread, and shape for the continuous variables broken down by treatment group, generate five-number summaries, detect outliers, and fit distributions to the skewed fitness variable to confirm it is gamma rather than normal. This stage exists because no inference is trustworthy until you understand the data's structure, and the descriptive findings here will directly inform which tests are valid in the next stage. By the end you will have a complete descriptive foundation on which the hypothesis testing and estimation will rest.
Prerequisites
- Python 3.10 or later with NumPy, SciPy, and pandas installed.
- The capstone dataset cricket_trial.csv generated in Lesson 31.
- Mastery of central tendency, spread, and shape from Module 1.
- Understanding of distribution fitting and goodness-of-fit from Module 3.
- Comfort with pandas grouping and aggregation operations.
Setup & Project Structure
You will work in the capstone project directory alongside the dataset, creating a descriptive-analysis module that loads the data and produces the summary. Keeping each capstone stage in its own module while sharing the dataset keeps the growing analysis organised and lets each stage be reviewed independently. Ensure the dataset from Lesson 31 is present, and import the same libraries so the analysis is consistent across stages.
# In the capstone project directory (contains cricket_trial.csv)
touch descriptive_analysis.py
# Verify the dataset is present
python -c "import pandas as pd; df = pd.read_csv('cricket_trial.csv'); print(f'{len(df)} rows loaded')"
Step 1 — Foundation
Step 1 builds the foundational group-wise descriptive summary: a function that computes the mean, median, standard deviation, and IQR for a continuous variable, broken down by treatment group. This is the foundation because comparing the treatment and control groups descriptively is the first glimpse of whether the regime had an effect, and these summaries frame every later inference. Computing both mean and median lets you immediately spot skew through their divergence, applying a Module 1 diagnostic to the real data.
# descriptive_analysis.py
import numpy as np
import pandas as pd
trial = pd.read_csv("cricket_trial.csv")
def group_summary(df, column, group_col="group"):
"""Central tendency and spread for a column, split by group."""
summary = {}
for grp, sub in df.groupby(group_col)[column]:
q1, q3 = np.percentile(sub, [25, 75])
summary[grp] = {
"n": len(sub),
"mean": sub.mean(),
"median": sub.median(),
"std": sub.std(ddof=1),
"iqr": q3 - q1,
"mean_median_gap": sub.mean() - sub.median(), # skew hint
}
return summary
# Strike rate improvement = after - before
trial["improvement"] = trial["strike_after"] - trial["strike_before"]
for grp, stats_d in group_summary(trial, "improvement").items():
print(f"{grp:10}: mean={stats_d['mean']:.2f}, median={stats_d['median']:.2f}, "
f"std={stats_d['std']:.2f}")
Step 2 — Core Logic
Step 2 adds the shape and outlier analysis: a function producing the five-number summary, skewness, excess kurtosis, and IQR-fence outlier detection for any variable. This is the analytical core of the descriptive stage because it characterises the distribution's shape and flags anomalies, directly determining whether parametric tests will be valid later. Applying this to the skewed fitness variable will reveal its right skew, foreshadowing the need for non-parametric handling in the inference stage.
# descriptive_analysis.py (continued)
from scipy import stats
def shape_analysis(values):
"""Five-number summary, shape statistics, and IQR-fence outliers."""
values = np.asarray(values)
q1, q3 = np.percentile(values, [25, 75])
iqr = q3 - q1
lo, hi = q1 - 1.5 * iqr, q3 + 1.5 * iqr
skew = stats.skew(values)
return {
"five_number": {
"min": float(values.min()), "q1": float(q1),
"median": float(np.median(values)), "q3": float(q3),
"max": float(values.max()),
},
"skewness": skew,
"excess_kurtosis": stats.kurtosis(values),
"shape": ("right-skewed" if skew > 0.5 else
"left-skewed" if skew < -0.5 else "symmetric"),
"outliers": values[(values < lo) | (values > hi)].tolist(),
}
fitness_shape = shape_analysis(trial["fitness"])
print(f"Fitness shape: {fitness_shape['shape']}, skew={fitness_shape['skewness']:.2f}")
print(f"Fitness outliers: {len(fitness_shape['outliers'])} flagged")
Step 3 — Integration & Enhancement
Step 3 integrates distribution fitting to formally characterise the fitness variable, confirming with goodness-of-fit testing that it follows a gamma rather than a normal distribution. This completes the descriptive stage by moving from informal shape description to a validated distributional model, applying the Module 3 fitting-and-validation workflow to the real capstone data. The confirmed distribution both documents the data's nature and justifies the non-parametric choices the inference stage will make for this variable.
# descriptive_analysis.py (continued)
def characterise_distribution(values, candidates=("norm", "gamma", "lognorm")):
"""Fit candidates and pick the best by KS goodness-of-fit p-value."""
values = np.asarray(values)
results = {}
for name in candidates:
dist = getattr(stats, name)
params = dist.fit(values)
ks_stat, ks_p = stats.kstest(values, name, args=params)
results[name] = {"params": params, "ks_p": ks_p}
best = max(results, key=lambda k: results[k]["ks_p"])
return best, results
best_dist, fit_results = characterise_distribution(trial["fitness"])
print(f"Best-fitting distribution for fitness: '{best_dist}'")
for name, r in fit_results.items():
print(f" {name:8}: KS p-value = {r['ks_p']:.4f}")
print("Expected: gamma fits well, normal is rejected -> use non-parametric later.")
Step 4 — Testing & Verification
Now you will run the complete descriptive analysis and verify the findings match the dataset's known construction. Confirm the treatment group shows a larger mean improvement than control, that the fitness variable is identified as right-skewed and best fit by the gamma distribution, and that outlier counts are reasonable. These descriptive findings recovering the embedded ground truth verify your analysis is correct and set up the inference stage.
# Run the full descriptive analysis
import pandas as pd
from descriptive_analysis import (trial, group_summary, shape_analysis,
characterise_distribution)
print("=== TREATMENT EFFECT (descriptive) ===")
for grp, s in group_summary(trial, "improvement").items():
print(f" {grp:10}: mean improvement = {s['mean']:.2f}")
print("\n=== FITNESS DISTRIBUTION ===")
fs = shape_analysis(trial["fitness"])
print(f" Shape: {fs['shape']}, skewness: {fs['skewness']:.2f}")
best, _ = characterise_distribution(trial["fitness"])
print(f" Best distribution: {best}")
# Expected: treatment mean improvement (~9) > control (~1);
# fitness right-skewed, best fit gamma -> confirms ground truth.
Warning: Do not compute group means and immediately conclude the treatment works — descriptive differences are observations, not inferences. A larger mean improvement in the treatment group is only a hint; it could still arise from chance, and only the hypothesis testing in the next stage can establish whether the difference is real. Resist the strong temptation to draw conclusions from descriptive statistics alone, which is a classic way analyses overreach beyond what the evidence supports.
Extension Challenge: Extend the descriptive analysis to produce the same group-wise summaries broken down further by player role, revealing whether the regime's apparent effect differs across batsmen, bowlers, and allrounders. As a stretch goal, generate diagnostic plots — grouped boxplots of improvement and a histogram of fitness with the fitted gamma density overlaid — so the descriptive findings are communicated visually as well as numerically.
- Descriptive analysis must precede inference; understanding the data's structure determines which tests are valid.
- Group-wise summaries of mean, median, spread, and IQR give the first glimpse of a treatment effect.
- The mean-median gap is a free diagnostic of skew applied directly to the real data.
- Shape statistics and IQR-fence outlier detection characterise distributions and flag anomalies for later test choices.
- Distribution fitting with goodness-of-fit validation confirms the fitness variable is gamma, justifying non-parametric handling.
- Descriptive differences are observations, not conclusions; only hypothesis testing can establish whether an effect is real.